JavaScript基礎(chǔ)之this詳解
JavaScript的this和Java等面向?qū)ο笳Z(yǔ)言中的this大不一樣,bind()、call()和apply()函數(shù)更是將this的靈活度進(jìn)一步延伸。
為了保證可讀性,本文采用意譯而非直譯。另外,本文版權(quán)歸原作者所有,翻譯僅用于學(xué)習(xí)。
如果對(duì)JavaScript的關(guān)鍵字this理解不夠深刻,有時(shí)候會(huì)掉入意想不到的坑。在這里我們總結(jié)了5條通用規(guī)則來(lái)幫助你判斷this到底指向什么。雖然沒(méi)有囊括所有的情況,但日常大部分情況都可以使用這些規(guī)則來(lái)正確推斷。
this的值通常是由所在函數(shù)的執(zhí)行環(huán)境決定,也就是說(shuō)要看函數(shù)是如何被調(diào)用的;
同一個(gè)函數(shù)每一次調(diào)用,this都可能指向不同的對(duì)象;
全局對(duì)象 (Global Object)
打開(kāi)Chrome瀏覽器開(kāi)發(fā)者面板(Windows: Ctrl + Shift + J)(Mac: Cmd + Option + J),并且輸入:
console.log(this);
看看輸出了什么?
// Window {}
window對(duì)象! 因?yàn)樵谌肿饔糜蛳拢瑃his指向全局對(duì)象。在瀏覽器中全局對(duì)象就是window對(duì)象。
為了讓你更加清楚理解為什么this會(huì)指向window對(duì)象,我們來(lái)看另外一個(gè)例子:
var myName = 'Brandon';
我們可以通過(guò)在控制臺(tái)輸入myName來(lái)訪問(wèn)其值:
myName // 輸出 'Brandon'
其實(shí),所有在全局定義的變量都綁定到window對(duì)象。我們來(lái)做如下測(cè)試:
window.myName // 輸出 'Brandon' window.myName === myName // 輸出 true
現(xiàn)在我們將this放到函數(shù)內(nèi)部,看看有何效果。
function test(){
return this;
}
test();
你會(huì)發(fā)現(xiàn)this依然指向全局的window對(duì)象。因?yàn)閠his關(guān)鍵字沒(méi)有處于一個(gè)聲明的對(duì)象內(nèi)部,默認(rèn)指向全局window對(duì)象。這一點(diǎn)可能對(duì)于大部分初學(xué)者來(lái)說(shuō)有點(diǎn)難以理解。當(dāng)讀完這篇文章,你就會(huì)豁然開(kāi)朗。
注意:如果在strcit模式下,上面的例子中this為undefined。
聲明的對(duì)象 (Declared Object)
當(dāng)this關(guān)鍵字在一個(gè)聲明對(duì)象內(nèi)部使用,其值會(huì)被綁定到調(diào)用該this的函數(shù)的最近的父對(duì)象。我們用例子來(lái)說(shuō)明這個(gè)問(wèn)題:
var person = {
first: 'John',
last: 'Smith',
full: function() {
console.log(this.first + ' ' + this.last);
}
};
person.full();
// 輸出 'John Smith'
在被聲明的對(duì)象person中的full函數(shù)里面使用了this, 那么調(diào)用this的full函數(shù)的最近的父對(duì)象就是person, 因此,this指向person。
為了更好的描述this實(shí)際上是指向person對(duì)象的,你可以拷貝如下代碼到瀏覽器控制臺(tái),將this打印出來(lái)。
var person = {
first: 'John',
last: 'Smith',
full: function() {
console.log(this);
}
};
person.full();
// 輸出 Object {first: "John", last: "Smith", full: function}
我們接下來(lái)看一個(gè)更復(fù)雜的例子:
var person = {
first: 'John',
last: 'Smith',
full: function() {
console.log(this.first + ' ' + this.last);
},
personTwo: {
first: 'Allison',
last: 'Jones',
full: function() {
console.log(this.first + ' ' + this.last);
}
}
};
在這里我們有嵌套的對(duì)象,在這個(gè)時(shí)候,this分別指向誰(shuí)呢? 我們將其打印出來(lái)看一看:
person.full(); // 輸出 'John Smith' person.personTwo.full(); // 輸出 'Allison Jones'
你會(huì)發(fā)現(xiàn)滿足我們前面所描述的規(guī)則:其值會(huì)被綁定到調(diào)用this的函數(shù)的最近的父對(duì)象。
new關(guān)鍵字
當(dāng)使用new關(guān)鍵字構(gòu)建一個(gè)新的對(duì)象,this會(huì)綁定到這個(gè)新對(duì)象。我們來(lái)看一個(gè)例子:
function Car(make, model) {
this.make = make;
this.model = model;
};
根據(jù)第一條規(guī)則,你可能會(huì)推斷this指向全局對(duì)象。但是如果我們使用new關(guān)鍵字來(lái)聲明一個(gè)新的變量,Car函數(shù)中的this將會(huì)綁定一個(gè)新的空對(duì)象,然后初始化this.make和this.model的值。
var myCar = new Car('Ford', 'Escape');
console.log(myCar);
// 輸出 Car {make: "Ford", model: "Escape"}
call, bind, 和apply
我們可以顯示的在call(),bind(),apply()中設(shè)置this的綁定對(duì)象。這三個(gè)函數(shù)很類似,但是我們需要注意它們微小的區(qū)別。
<!-- call可以接收任意個(gè)數(shù)的參數(shù),其中第一個(gè)必須是一個(gè)this對(duì)象,其余依次是所有的參數(shù)。 -->
我們來(lái)看一個(gè)例子:
function add(c, d) {
console.log(this.a + this.b + c + d);
}
add(3,4);
// 輸出 NaN
add函數(shù)輸出NaN, 因?yàn)閠his.a和this.b未定義。
現(xiàn)在我們引入對(duì)象,并且使用call()和apply()來(lái)調(diào)用:
function add(c, d) {
console.log(this.a + this.b + c + d);
}
var ten = {a: 1, b: 2};
add.call(ten, 3, 4);
// 輸出 10
add.apply(ten, [3,4]);
// 輸出 10
當(dāng)我們使用add.call(),第一個(gè)參數(shù)是this需要綁定的對(duì)象,剩下的是add函數(shù)本來(lái)的參數(shù)。
因此,this.a指向ten.a,this.b指向ten.b。add.apply()也類似,除了第二個(gè)參數(shù)是一個(gè)數(shù)組,用于存儲(chǔ)add函數(shù)的參數(shù)。
bind()函數(shù)和call()類似,但是bind()函數(shù)不會(huì)立即被調(diào)用。bind()函數(shù)會(huì)返回一個(gè)函數(shù),并且將this綁定好。接下來(lái)我們來(lái)用例子來(lái)幫助理解bind()函數(shù)的應(yīng)用場(chǎng)景:
var small = {
a: 1,
go: function(b,c,d){
console.log(this.a+b+c+d);
}
}
var large = {
a: 100
}
執(zhí)行:
small.go(2, 3, 4); // 輸出 10
如果我們想使用large.a的值,而不是small.a呢? 我們可以使用call/apply:
small.go.call(large, 2, 3, 4); // 輸出 109
但是,如果我們現(xiàn)在還不知道這三個(gè)參數(shù)應(yīng)該傳入什么值,應(yīng)該怎么辦呢? 我們可以使用bind:
var bindTest = small.go.bind(large, 2);
如果我們將bindTest在控制臺(tái)下打印出來(lái),我們會(huì)看到:
console.log(bindTest);
// 輸出 function (b,c,d){console.log(this.a+b+c+d);}
注意:該函數(shù)已經(jīng)將this綁定到large對(duì)象,并且傳入了第一個(gè)參數(shù)b。所以,我們接下來(lái)是需要傳入余下的參數(shù)即可:
bindTest(3, 4); // 輸出 109
箭頭函數(shù)(=>)
因?yàn)樾枰艽蟮钠?,我們?huì)專門(mén)寫(xiě)一篇博客來(lái)介紹。
結(jié)論
當(dāng)你讀完這篇博客,你應(yīng)該可以理解大多數(shù)情況下this指向的對(duì)象。
接下來(lái)我們來(lái)總結(jié)一下:
this的值通常是由當(dāng)前函數(shù)的執(zhí)行環(huán)境所決定;
在全局作用域,this指向全局對(duì)象 (window對(duì)象);
當(dāng)使用new關(guān)鍵字聲明,this指向新建對(duì)象;
我們可以使用call(), bind(), apply()來(lái)設(shè)置this;
箭頭函數(shù)不會(huì)綁定this。
原文: JavaScript: The Keyword ‘This' for Beginners
譯者: Fundebug
相關(guān)文章
Javascript模塊化編程(一)模塊的寫(xiě)法最佳實(shí)踐
Javascript模塊化編程,已經(jīng)成為一個(gè)迫切的需求。理想情況下,開(kāi)發(fā)者只需要實(shí)現(xiàn)核心的業(yè)務(wù)邏輯,其他都可以加載別人已經(jīng)寫(xiě)好的模塊但是,Javascript不是一種模塊化編程語(yǔ)言,它不支持類class,更遑論模塊module了2013-01-01
怎樣在JavaScript里寫(xiě)一個(gè)swing把數(shù)據(jù)插入數(shù)據(jù)庫(kù)
在JavaScript里寫(xiě)一個(gè)swing來(lái)實(shí)現(xiàn)確定取消,來(lái)決定是否執(zhí)行這個(gè)功能 控制把數(shù)據(jù)插入數(shù)據(jù)庫(kù),接下來(lái)介紹實(shí)現(xiàn)方法2012-12-12
JavaScript基礎(chǔ)知識(shí)之?dāng)?shù)據(jù)類型
JavaScript中有5種簡(jiǎn)單數(shù)據(jù)類型(也稱為基本數(shù)據(jù)類型):Undefined、Null、Boolean、Number和String。還有1種復(fù)雜數(shù)據(jù)類型——Object,Object本質(zhì)上是由一組無(wú)序的名值對(duì)組成的2012-08-08
使用?Next.js?Cli?快速搭建和運(yùn)行?Web?應(yīng)用
這篇文章主要介紹了使用?Next.js?Cli?快速搭建和運(yùn)行?Web?應(yīng)用,需要的朋友可以參考下2024-04-04
ECMAScript5(ES5)中bind方法使用小結(jié)
這篇文章主要介紹了ECMAScript5(ES5)中bind方法使用小結(jié),bind和call以及apply一樣,都是可以改變上下文的this指向的,需要的朋友可以參考下2015-05-05
Javascript圖像處理—亮度對(duì)比度應(yīng)用案例
上一篇文章,我們講解了圖像處理中的卷積操作和平滑(也就是模糊)處理,這篇文章我們進(jìn)行亮度和對(duì)比度的變化,有需要的朋友可以參考下2013-01-01
JavaScript開(kāi)發(fā)規(guī)范要求(規(guī)范化代碼)
作為一名開(kāi)發(fā)人員(WEB前端JavaScript開(kāi)發(fā)),不規(guī)范的開(kāi)發(fā)不僅使日后代碼維護(hù)變的困難,同時(shí)也不利于團(tuán)隊(duì)的合作,通常還會(huì)帶來(lái)代碼安全以及執(zhí)行效率上的問(wèn)題。2010-08-08
JS限制上傳圖片大小不使用控件在本地實(shí)現(xiàn)
文件上傳之前的檢測(cè),通常是通過(guò)文件名來(lái)判斷文件類型是否合法,但是要想檢測(cè)文件的大小很難辦到,除非在本地或者使用控件。使用JS可以輕松解決詞問(wèn)題,本文詳細(xì)介紹,需要了解的朋友可以參考下2012-12-12
javascript基礎(chǔ)語(yǔ)法——全面理解變量和標(biāo)識(shí)符
下面小編就為大家?guī)?lái)一篇javascript基礎(chǔ)語(yǔ)法——全面理解變量和標(biāo)識(shí)符。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧2016-06-06
國(guó)內(nèi)常用的js類庫(kù)大全(CDN公共庫(kù))
羅列這類js類庫(kù)希望能幫助到大家,下面類庫(kù)都支持CDN,所以不用擔(dān)心速度問(wèn)題,就算某個(gè)節(jié)點(diǎn)慢也不會(huì)影響全國(guó)其他地區(qū)的訪問(wèn)速度,支持jQuery,Bootstrap,angular,zepto等js庫(kù)的CDN地址2020-06-06

