JavaScript中this的四個(gè)綁定規(guī)則總結(jié)
前言
如果要問(wèn)javascript中哪兩個(gè)知識(shí)點(diǎn)容易混淆,作用域查詢(xún)和this機(jī)制絕對(duì)名列前茅。所以這篇文章開(kāi)始將介紹javascript中this的四個(gè)綁定規(guī)則,下面來(lái)一起看看吧。
綁定規(guī)則
1. 默認(rèn)綁定
獨(dú)立函數(shù)調(diào)用時(shí),this 指向全局對(duì)象,如果使用嚴(yán)格模式,那么全局對(duì)象無(wú)法使用默認(rèn)綁定, this綁定至 undefined。
function foo() {
console.log(this.a);
}
var a = 2;
foo(); // 2
嚴(yán)格模式時(shí):
function foo() {
"use strict";
console,log(this.a);
}
var a = 2;
foo(); // TypeError: this is undefined
2. 隱式綁定
當(dāng)函數(shù)引用有上下文對(duì)象時(shí)(即函數(shù)作為引用屬性被添加到對(duì)象中),隱式綁定規(guī)則會(huì)把函數(shù)調(diào)用中的 this 綁定到這個(gè)上下文對(duì)象。
function foo() {
console.log( this.a);
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); // 2
對(duì)象屬性引用鏈中只有最頂層或者說(shuō)最后一層會(huì)影響調(diào)用位置:
obj1.obj2.foo(); // foo 中的 this 與 obj2 綁定
2.1 隱式丟失
隱式丟失指的是函數(shù)中的 this 丟失綁定對(duì)象,即它會(huì)應(yīng)用第 1 條的默認(rèn)綁定規(guī)則,從而將 this 綁定到全局對(duì)象或者 undefined 上,取決于是否在嚴(yán)格模式下運(yùn)行。以下情況會(huì)發(fā)生隱式丟失:
綁定至上下文對(duì)象的函數(shù)被賦值給一個(gè)新的函數(shù),然后調(diào)用這個(gè)新的函數(shù)時(shí):
function foo() {
console.log( this.a);
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; //函數(shù)別名
var a = "這是全局變量喔";
bar(); // "這是全局變量喔"
傳入回調(diào)函數(shù)時(shí):
function foo() {
console.log( this.a);
}
function doFoo(fn) {
fn(); // <-- 調(diào)用位置
}
var obj = {
a: 2,
foo: foo
};
var a = "這是全局變量喔";
doFoo( obj.foo ); // "這是全局變量喔"
其實(shí)這就是第一種情況的變種,實(shí)際上參數(shù)傳遞就是一種隱式賦值。除了開(kāi)發(fā)人員自定義的函數(shù),在將函數(shù)傳入語(yǔ)言?xún)?nèi)置的函數(shù)比如 setTimeout 時(shí),同樣會(huì)發(fā)生隱式丟失的情況。
3. 顯式綁定
顯式綁定的核心是 JavaScript 內(nèi)置的 call(..) 和 apply(..) 方法,這兩個(gè)方法在 JavaScript 提供的絕大多數(shù)函數(shù)以及開(kāi)發(fā)者自己創(chuàng)建的所有函數(shù)上都可以使用。
call(..) 和 apply(..)的第一個(gè)參數(shù)是一個(gè)對(duì)象(二者區(qū)別在后面?zhèn)魅氲膮?shù)形式,這里不是重點(diǎn),不討論),他們會(huì)將 this 綁定到這個(gè)對(duì)象上。因?yàn)槟憧梢灾苯又付?this 綁定的對(duì)象,所以這條規(guī)則被稱(chēng)為顯式綁定。
function foo() {
console.log( this.a);
}
var obj = {
a: 2
};
foo.call(obj); // 2
如果 call 或者 apply 傳入的第一個(gè)參數(shù)是原始值(字符串類(lèi)型、布爾類(lèi)型或者數(shù)字類(lèi)型),那么該原始值會(huì)被轉(zhuǎn)換成它的對(duì)象形式(new String() 、new Boolean() 或 new Number() ),俗稱(chēng)“裝箱”。
顯式綁定仍然無(wú)法解決丟失綁定問(wèn)題。
3.1 硬綁定
作為顯式綁定的一個(gè)變種,硬綁定可以解決丟失綁定問(wèn)題。
function foo() {
console.log( this.a);
}
var obj = {
a: 2
};
var bar = function() {
foo.call(obj);
};
bar(); // 2
setTimeout(bar, 100); // 2
bar.call(window); //無(wú)效,硬綁定的 bar 不會(huì)再修改它的 this
在一個(gè)新的函數(shù)內(nèi)部強(qiáng)制綁定 this 到某個(gè)對(duì)象上,無(wú)論之后如何調(diào)用這個(gè)新的函數(shù),其 this 都不會(huì)丟失。
典型應(yīng)用場(chǎng)景為創(chuàng)建一個(gè)包裹函數(shù),傳入所有的參數(shù)并返回接收到的所有值:
function foo(something) {
console.log(this.a, something);
return this.a + something;
}
var obj = {
a:2
};
var bar = function() {
return foo.call(obj, arguments);
};
var b = bar(3); // 2 3
console.log(b); // 5
或者將綁定的對(duì)象改為可配置,這樣就成了一個(gè)輔助綁定函數(shù):
...
function bind(fn, obj){
return function(){
return fn.apply(obj, arguments);
};
}
...
由于硬綁定實(shí)在太過(guò)常見(jiàn),所以 ES5 提供了內(nèi)置的 Function.prototype.bind,其用法如下:
function foo(something) {
console.log(this.a, something);
return this.a + something;
}
var obj = {
a: 2
};
var bar = foo.bind(obj);
var b = bar(3); // 2 3
console.log(b); // 5
3.2 API 調(diào)用的“上下文”
JavaScript 自身以及許多第三方庫(kù)的函數(shù)都提供了一個(gè)可選的參數(shù),通常被稱(chēng)為“上下文”,其作用和 bind(..) 一樣,確保回調(diào)函數(shù)使用指定的 this。
function foo(el) {
console.log( el, this.id);
}
var obj = {
id: "awsome"
};
//調(diào)用 foo(..) 時(shí)把 this 綁定到 obj
[1,2,3].forEach(foo, obj);
// 1 awsome 2 awsome 3 awsome
實(shí)際上這些函數(shù)背后還是調(diào)用了 call() 或者 apply() ,只不過(guò)這樣開(kāi)發(fā)者需要寫(xiě)的代碼就少了一些。
4. new 綁定
使用 new 來(lái)調(diào)用函數(shù)時(shí),會(huì)自動(dòng)執(zhí)行下面的操作:
1、創(chuàng)建一個(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() {
this.a = a;
}
var bar = new foo(2);
console.log(bar.a); // 2
使用 new 來(lái)調(diào)用 foo(..) 時(shí),會(huì)構(gòu)造一個(gè)新對(duì)象并把它綁定到 foo(..) 調(diào)用中的 this 上。
優(yōu)先級(jí)
具體推斷細(xì)節(jié)不再表述,以上四種綁定規(guī)則的使用先后推斷如下:
1、函數(shù)是否在 new 中調(diào)用(new 綁定)?如果是的話 this 綁定的是新創(chuàng)建的對(duì)象。
var bar = new foo();
2、函數(shù)是否通過(guò) call、apply (顯示綁定)或者硬綁定?如果是的話,this 綁定的是指定的對(duì)象。
var bar = foo.call(obj2);
3、函數(shù)是否在某個(gè)上下文對(duì)象中調(diào)用(隱式綁定)?如果是的話,this 綁定的是那個(gè)上下文對(duì)象。
var bar = obj1.foo();
4、如果都不是的話,使用默認(rèn)綁定。如果在嚴(yán)格模式下,就綁定到 undefined,否則綁定到全局對(duì)象。
var bar = foo();
綁定例外
如果把 null 或者 undefined 作為 this 的綁定對(duì)象傳入 call、apply 或者 bind,那么這些值在調(diào)用時(shí)會(huì)被忽略,實(shí)際應(yīng)用的是默認(rèn)綁定規(guī)則。(書(shū)中推薦使用一個(gè)空對(duì)象來(lái)綁定 this)。
間接引用。這種情況容易在賦值時(shí)發(fā)生:
function foo() {
console.log( this.a);
}
var a = 2;
var o = {a: 3, foo: foo};
var p = {a: 4};
o.foo(); // 3
(p.foo = o.foo)(); // 2
p.foo() 實(shí)際上引用了 foo() ,如此,會(huì)應(yīng)用默認(rèn)綁定。
另外ES6 對(duì)改變 this 的混亂綁定作了相應(yīng)的努力,誕生了箭頭函數(shù),其根據(jù)當(dāng)前詞法作用域來(lái)決定 this 而非上面的四條規(guī)則,具體來(lái)說(shuō),箭頭函數(shù)會(huì)繼承外層函數(shù)調(diào)用的 this 綁定(這其實(shí)和 ES6 之前代碼中的 self = this 是一個(gè)道理)。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容,希望能對(duì)大家的學(xué)習(xí)或者工作帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流。
相關(guān)文章
js獲取上傳文件的絕對(duì)路徑實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇js獲取上傳文件的絕對(duì)路徑實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08
javascript 無(wú)提示關(guān)閉窗口腳本
在IE7、IE8中,使用JavaScript提供的close()方法都可以關(guān)閉當(dāng)前窗口或標(biāo)簽,但都提示討厭的對(duì)話框,找了下代碼,終于可以無(wú)提示直接關(guān)閉了。2009-08-08
js實(shí)現(xiàn)計(jì)時(shí)器秒表功能
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)計(jì)時(shí)器秒表功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12
前端面試運(yùn)行npm?run?xxx發(fā)生過(guò)程原理解析
這篇文章主要為大家介紹了前端面試運(yùn)行npm?run?xxx過(guò)程原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
微信小程序動(dòng)態(tài)評(píng)分展示/五角星展示/半顆星展示/自定義長(zhǎng)度展示功能的實(shí)現(xiàn)
這篇文章主要介紹了微信小程序動(dòng)態(tài)評(píng)分展示/五角星展示/半顆星展示/自定義長(zhǎng)度展示的實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07
解決layui富文本編輯器圖片上傳無(wú)法回顯的問(wèn)題
今天小編就為大家分享一篇解決layui富文本編輯器圖片上傳無(wú)法回顯的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09
JS 設(shè)計(jì)模式之:?jiǎn)卫J蕉x與實(shí)現(xiàn)方法淺析
這篇文章主要介紹了JS 設(shè)計(jì)模式之:?jiǎn)卫J?結(jié)合實(shí)例形式分析了JS 單例模式原理、定義、實(shí)現(xiàn)方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2020-05-05

