聊聊 JavaScript 中的 this

JavaScript 中的 this 一直是比較讓人頭疼,也是面試特別容易問(wèn)及的問(wèn)題。下面就參照這《你不知道的 JavaScript》來(lái)學(xué)習(xí)下 this 這個(gè)神奇的東西。

this 到底指向何處

this 是在運(yùn)行時(shí)進(jìn)行綁定的,并不是在編寫時(shí)綁定,它的上下文取決于函數(shù)調(diào)用時(shí)的各種條件。 this 的綁定和函數(shù)聲明的位置沒(méi)有任何關(guān)系,只取決于函數(shù)的調(diào)用方式。

所以,this 并不只是簡(jiǎn)單地指向函數(shù)或者對(duì)象自身。

this 的四種綁定方式

默認(rèn)綁定

所謂的默認(rèn)綁定就是 this 的默認(rèn)綁定方式。

function foo() {
    console.log(this.a)
}

var a = 3;

foo(); // 3

注意:嚴(yán)格模式下這種默認(rèn)綁定形式不成立。

var a = 3;

function foo() {
    "use strict";
    console.log(this.a)
}

foo(); // TypeError

隱式綁定

隱式綁定是指 this 所在函數(shù)在有上下文的前提下的綁定,如 obj.foo();

function foo() {
    console.log(this.a);
}

var a = 1;
var obj = {
    a: 2,
    foo: foo
};

obj.foo(); // 2

注意:對(duì)象中的函數(shù)只是引用關(guān)系,即對(duì)象和函數(shù)存在于兩個(gè)地方。所以在別的地方使用函數(shù),與隱式綁定的對(duì)象就沒(méi)有關(guān)系了。看下兩個(gè)例子:

  1. 其中 var myFoo = obj.foo 的 myFoo 變量引用的是 foo() 函數(shù),與 obj 并無(wú)關(guān)系。所以 myFoo 的執(zhí)行函數(shù)行為就變成了默認(rèn)綁定,打印結(jié)果為 1。
function foo() {
    console.log(this.a);
}

var a = 1;
var obj = {
    a: 2,
    foo: foo
};

var myFoo = obj.foo
myFoo(); // 默認(rèn)綁定,值為 1
  1. 在回調(diào)函數(shù)中其實(shí)也會(huì)出現(xiàn) this 綁定丟失的情況,回調(diào)函數(shù) obj.foo 引用的是 foo 函數(shù),與 obj 對(duì)象并無(wú)關(guān)系。
function foo() {
    console.log(this.a);
}

var a = 1;
var obj = {
    a: 2,
    foo: foo
};

setTimeout(obj.foo, 300); // 1

顯示綁定

顯式綁定就是指使用 call、apply、bind 來(lái)指定某個(gè)上下文進(jìn)行綁定,它們的一個(gè)作用就只為函數(shù)硬綁定一個(gè)上下文對(duì)象。

之前的回調(diào)函數(shù)使用 bind 進(jìn)行修改后打印出了我們 obj 對(duì)象中的 a 屬性:

function foo() {
    console.log(this.a);
}

var a = 1;
var obj = {
    a: 2,
    foo: foo
};

setTimeout(obj.foo.bind(obj), 300);

call 和 apply 也是類似的,通過(guò)對(duì)函數(shù)指定上下文來(lái)進(jìn)行硬綁定,且硬綁定只能綁定一次。

call() 方法的作用和 apply() 方法類似,區(qū)別就是 call() 方法接受的是參數(shù)列表,而 apply() 方法接受的是一個(gè)參數(shù)數(shù)組。

new綁定

new 關(guān)鍵字創(chuàng)建對(duì)象的過(guò)程其實(shí)也是一個(gè)綁定上下文的過(guò)程,所以使用 new 創(chuàng)建的對(duì)象的 this 也要格外注意。

使用 new 來(lái)調(diào)用函數(shù),或者說(shuō)發(fā)生構(gòu)造函數(shù)調(diào)用時(shí),會(huì)自動(dòng)執(zhí)行下面的操作。

  1. 創(chuàng)建(或者說(shuō)構(gòu)造)一個(gè)全新的對(duì)象。
  2. 這個(gè)新對(duì)象會(huì)被執(zhí)行 [[ 原型 ]] 連接。
  3. 這個(gè)新對(duì)象會(huì)綁定到函數(shù)調(diào)用的 this 。
  4. 如果函數(shù)沒(méi)有返回其他對(duì)象,那么 new 表達(dá)式中的函數(shù)調(diào)用會(huì)自動(dòng)返回這個(gè)新對(duì)象。
function foo(a) {
  this.a = a;
}
var bar = new foo(2);
console.log( bar.a ); // 2

可以看到 new 行為的第三步就是進(jìn)行 this 綁定,我們也可以從代碼看到 new 行為的確有綁定 this 的能力。

this 四種綁定方式排序

既然四種綁定都能夠改變 this 的指向,那么這四種綁定的優(yōu)先級(jí)是怎樣的呢?結(jié)論是:

new 綁定 > 顯示綁定 > 隱式綁定 > 默認(rèn)綁定

雖然很少會(huì)出現(xiàn)多個(gè)場(chǎng)景綁定一個(gè) this 的情況,但是知道下也能以防萬(wàn)一。

箭頭函數(shù)

關(guān)于 this 最后要說(shuō)的就是 ES6 的箭頭函數(shù)。

function foo() {
    setTimeout(() => {
        // 這里的 this 在此法上繼承自 foo()
        console.log(this.a);
    }, 100);
}
var obj = {
    a: 2
};
foo.call(obj); // 2

它完全等同于:

function foo() {
    var self = this; // lexical capture of this
    setTimeout(function () {
        console.log(self.a);
    }, 100);
}
var obj = {
    a: 2
};
foo.call(obj); // 2

關(guān)于箭頭函數(shù)只要記住 var self = this; 就夠了。

它其實(shí)是通過(guò)詞法作用域保存當(dāng)前 this 上下文傳遞給回調(diào)函數(shù)。本質(zhì)上是拋棄了 this 原有的機(jī)制。

最后

我們從四種常見(jiàn) this 綁定方式和箭頭函數(shù)這兩個(gè)角度系統(tǒng)的學(xué)習(xí)了 this 綁定的知識(shí)點(diǎn),相信之后你再也不怕 this 相關(guān)的知識(shí)點(diǎn)了!

本文還有很多可以改進(jìn)的地方,如有任何意見(jiàn)和問(wèn)題,歡迎留言指出。謝謝~

推薦資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 關(guān)于 this this 關(guān)鍵字是 JavaScript 中最復(fù)雜的機(jī)制之一。它是一個(gè)很特別的關(guān)鍵字,被自動(dòng)定義在...
    游學(xué)者灬墨槿閱讀 634評(píng)論 1 2
  • 1.概念 在JavaScript中,this 是指當(dāng)前函數(shù)中正在執(zhí)行的上下文環(huán)境,因?yàn)檫@門語(yǔ)言擁有四種不同的函數(shù)調(diào)...
    BluesCurry閱讀 1,239評(píng)論 0 2
  • 1.函數(shù)調(diào)用棧和調(diào)用位置 在函數(shù)執(zhí)行的時(shí)候,會(huì)有一個(gè)活動(dòng)記錄(也叫執(zhí)行上下文)來(lái)記錄函數(shù)的調(diào)用順序,這個(gè)就是函數(shù)調(diào)...
    lightNate閱讀 607評(píng)論 1 14
  • 1. this之謎 在JavaScript中,this是當(dāng)前執(zhí)行函數(shù)的上下文。因?yàn)镴avaScript有4種不同的...
    百里少龍閱讀 1,103評(píng)論 0 3
  • 宋凝懷中的小絨球不說(shuō)話,就這么安靜乖巧地掛在宋凝身上,也不肯撒手。 “明日是姝兒生辰,阿凝準(zhǔn)備了三個(gè)禮物送給你。”...
    c811c58c875f閱讀 411評(píng)論 0 0

友情鏈接更多精彩內(nèi)容