前端開發(fā)初學(xué)者必須了解的“this”關(guān)鍵字
如果對JavaScript的關(guān)鍵字this理解不夠深刻,有時(shí)候會掉入意想不到的坑。在這里我們總結(jié)了5條通用規(guī)則來幫助你判斷this到底指向什么。雖然沒有囊括所有的情況,但日常大部分情況都可以使用這些規(guī)則來正確推斷。
- this的值通常是由所在函數(shù)的執(zhí)行環(huán)境決定,也就是說要看函數(shù)是如何被調(diào)用的;
 - 同一個(gè)函數(shù)每一次調(diào)用,this都可能指向不同的對象;
 
全局對象 (Global Object)
打開Chrome瀏覽器開發(fā)者面板(Windows: Ctrl + Shift + J)(Mac: Cmd + Option + J),并且輸入:
- console.log(this);
 
看看輸出了什么?
- // Window {}
 
window對象! 因?yàn)樵谌肿饔糜蛳?,this指向全局對象。在瀏覽器中全局對象就是window對象。
為了讓你更加清楚理解為什么this會指向window對象,我們來看另外一個(gè)例子:
- var myName = 'Brandon';
 
我們可以通過在控制臺輸入myName來訪問其值:
- myName
 - // 輸出 'Brandon'
 
其實(shí),所有在全局定義的變量都綁定到window對象。我們來做如下測試:
- window.myName
 - // 輸出 'Brandon'
 - window.myName === myName
 - // 輸出 true
 
現(xiàn)在我們將this放到函數(shù)內(nèi)部,看看有何效果。
- function test(){
 - return this;
 - }
 - test();
 
你會發(fā)現(xiàn)this依然指向全局的window對象。因?yàn)閠his關(guān)鍵字沒有處于一個(gè)聲明的對象內(nèi)部,默認(rèn)指向全局window對象。這一點(diǎn)可能對于大部分初學(xué)者來說有點(diǎn)難以理解。當(dāng)讀完這篇文章,你就會豁然開朗。
注意:如果在strcit模式下,上面的例子中this為undefined。
聲明的對象 (Declared Object)
當(dāng)this關(guān)鍵字在一個(gè)聲明對象內(nèi)部使用,其值會被綁定到調(diào)用該this的函數(shù)的最近的父對象。我們用例子來說明這個(gè)問題:
- var person = {
 - first: 'John',
 - last: 'Smith',
 - full: function() {
 - console.log(this.first + ' ' + this.last);
 - }
 - };
 - person.full();
 - // 輸出 'John Smith'
 
在被聲明的對象person中的full函數(shù)里面使用了this, 那么調(diào)用this的full函數(shù)的最近的父對象就是person, 因此,this指向person。
為了更好的描述this實(shí)際上是指向person對象的,你可以拷貝如下代碼到瀏覽器控制臺,將this打印出來。
- var person = {
 - first: 'John',
 - last: 'Smith',
 - full: function() {
 - console.log(this);
 - }
 - };
 - person.full();
 - // 輸出 Object {first: "John", last: "Smith", full: function}
 
我們接下來看一個(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);
 - }
 - }
 - };
 
在這里我們有嵌套的對象,在這個(gè)時(shí)候,this分別指向誰呢? 我們將其打印出來看一看:
- person.full();
 - // 輸出 'John Smith'
 - person.personTwo.full();
 - // 輸出 'Allison Jones'
 
你會發(fā)現(xiàn)滿足我們前面所描述的規(guī)則:其值會被綁定到調(diào)用this的函數(shù)的最近的父對象。
new關(guān)鍵字
當(dāng)使用new關(guān)鍵字構(gòu)建一個(gè)新的對象,this會綁定到這個(gè)新對象。我們來看一個(gè)例子:
- function Car(make, model) {
 - this.make = make;
 - this.model = model;
 - };
 
根據(jù)***條規(guī)則,你可能會推斷this指向全局對象。但是如果我們使用new關(guān)鍵字來聲明一個(gè)新的變量,Car函數(shù)中的this將會綁定一個(gè)新的空對象,然后初始化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的綁定對象。這三個(gè)函數(shù)很類似,但是我們需要注意它們微小的區(qū)別。
我們來看一個(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)在我們引入對象,并且使用call()和apply()來調(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需要綁定的對象,剩下的是add函數(shù)本來的參數(shù)。
因此,this.a指向ten.a,this.b指向ten.b。add.apply()也類似,除了第二個(gè)參數(shù)是一個(gè)數(shù)組,用于存儲add函數(shù)的參數(shù)。
bind()函數(shù)和call()類似,但是bind()函數(shù)不會立即被調(diào)用。bind()函數(shù)會返回一個(gè)函數(shù),并且將this綁定好。接下來我們來用例子來幫助理解bind()函數(shù)的應(yī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在控制臺下打印出來,我們會看到:
- console.log(bindTest);
 - // 輸出 function (b,c,d){console.log(this.a+b+c+d);}
 
注意:該函數(shù)已經(jīng)將this綁定到large對象,并且傳入了***個(gè)參數(shù)b。所以,我們接下來是需要傳入余下的參數(shù)即可:
- bindTest(3, 4);
 - // 輸出 109
 
箭頭函數(shù)(->)
因?yàn)樾枰艽蟮钠?,我們會專門寫一篇博客來介紹。
結(jié)論
當(dāng)你讀完這篇博客,你應(yīng)該可以理解大多數(shù)情況下this指向的對象。
接下來我們來總結(jié)一下:
- this的值通常是由當(dāng)前函數(shù)的執(zhí)行環(huán)境所決定;
 - 在全局作用域,this指向全局對象 (window對象);
 - 當(dāng)使用new關(guān)鍵字聲明,this指向新建對象;
 - 我們可以使用call(), bind(), apply()來設(shè)置this;
 - 箭頭函數(shù)不會綁定this。
 
【本文為51CTO專欄作者“謝軍”的原創(chuàng)稿件,轉(zhuǎn)載可通過作者微信公眾號(jingfeng18)獲取聯(lián)系】















 
 
 





 
 
 
 