從學(xué)習(xí)前端開始已經(jīng)大概要兩個(gè)月了亮垫,這幾天突然發(fā)現(xiàn)this并沒有想想中這么簡(jiǎn)單,之前很長(zhǎng)一段時(shí)間對(duì)于this的認(rèn)識(shí)停留在它的指向方法上。
- 當(dāng)以方法的形式調(diào)用時(shí),this指向調(diào)用者
- 當(dāng)以函數(shù)的形式調(diào)用時(shí)做个,this指向window
- 當(dāng)以構(gòu)造函數(shù)的形式調(diào)用時(shí),this就是新創(chuàng)建的那個(gè)函數(shù)
- 而改變this指向的方法有兩種:apply和call
那時(shí)對(duì)this只是一個(gè)簡(jiǎn)單的認(rèn)識(shí)滚局,這么說來也沒有任何理解上的問題居暖。但是學(xué)到后來,發(fā)現(xiàn)this的應(yīng)用光靠這些基礎(chǔ)已經(jīng)遠(yuǎn)遠(yuǎn)不夠了藤肢。
從綁定方式上我姑且把它分為4種方式膝但。
默認(rèn)綁定
- 獨(dú)立函數(shù)調(diào)用:可以把這條規(guī)則看作是無法應(yīng)用其他規(guī)則時(shí)的默認(rèn)規(guī)則
- 獨(dú)立函數(shù)調(diào)用:如果使用了非嚴(yán)格模式,this 會(huì)綁定到全局對(duì)象(window)
- 獨(dú)立函數(shù)調(diào)用:如果使用嚴(yán)格模式( strict mode ),this 會(huì)綁定到 undefined
- 這里有一個(gè)微妙但是非常重要的細(xì)節(jié)谤草,雖然 this 的綁定規(guī)則完全取決于調(diào)用位置。
- 但是只有 foo()運(yùn)行在非 strict mode 下時(shí)莺奸,默認(rèn)綁定才能綁定到全局對(duì)象丑孩;
- 在嚴(yán)格模式底下foo()會(huì)綁給undefined
多說無用,下面來看代碼.
var a = 2;
function foo() {
console.log( this.a );
}
(function(){
"use strict";
foo();
})()
這個(gè)時(shí)候嚴(yán)格模式不會(huì)影響默認(rèn)綁定規(guī)則灭贷,此時(shí)輸出的是2
function foo() {
"use strict";
console.log( this.a );
}
var a = 2;
foo();
現(xiàn)在這個(gè)時(shí)候會(huì)報(bào)錯(cuò)温学,a為undefined.
隱式綁定
隱式綁定的規(guī)則是調(diào)用位置是否有上下文對(duì)象,或者說是否被某個(gè)對(duì)象擁有或者包含甚疟。當(dāng)函數(shù)引用有上下文對(duì)象時(shí)仗岖,隱式綁定規(guī)則會(huì)把函數(shù)調(diào)用中的 this 綁定到這個(gè)上下文對(duì)象
對(duì)象屬性引用鏈中只有最頂層或者說最后一層會(huì)影響調(diào)用位置
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
obj.foo();
毋庸置疑this指向調(diào)用者obj,輸出2
function foo() {
console.log( this.a );
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo();
這個(gè)時(shí)候this指向obj2览妖,輸出42
- 一個(gè)最常見的 this 綁定問題就是被隱式綁定的函數(shù)會(huì)丟失綁定對(duì)象轧拄,也就是說它會(huì)應(yīng)用默認(rèn)綁定,從而把 this 綁定到全局對(duì)象或者 undefined 上.(取決于是否是嚴(yán)格模式)
function foo() {
console.log( this.a );
}
var a = "hello word";
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo;
bar();
這個(gè)時(shí)候會(huì)發(fā)生隱式丟失讽膏,this指向全局對(duì)象:hello word
- 參數(shù)傳遞其實(shí)也是一種隱式賦值檩电,因此我們傳入函數(shù)時(shí)也會(huì)被隱式賦值
function foo() {
console.log( this.a );
}
function doFoo(fn) {
fn();
}
var a = "hello word";
var obj = {
a: 2,
foo: foo
};
doFoo( obj.foo );
這個(gè)時(shí)候會(huì)發(fā)生隱式丟失,this指向全局對(duì)象:hello word
如果你把函數(shù)傳入語(yǔ)言內(nèi)置的函數(shù)而不是傳入你自己聲明的函數(shù),你會(huì)發(fā)現(xiàn)結(jié)果是一樣的俐末,沒有區(qū)別,比如定時(shí)器的內(nèi)置函數(shù):
function foo() {
console.log( this.a );
}
var a = "hello word";
var obj = {
a: 2,
foo: foo
};
setTimeout( obj.foo, 1000 );
結(jié)果輸出的仍然是:hello word
顯示綁定
- 我們不想在對(duì)象內(nèi)部包含函數(shù)引用料按,而想在某個(gè)對(duì)象上強(qiáng)制調(diào)用函數(shù),具體點(diǎn)說,可以使用函數(shù)的 call(..) 和 apply(..) 方法來實(shí)現(xiàn)顯示綁定.
var a =0;
function foo() {
console.log( this.a );
}
var obj = {
a:1
};
var obj2 = {
a:2
};
var obj3 = {
a:3
};
foo();
foo.call( obj );
foo.apply( obj2 );
foo.call( obj3 );
如果沒有給foo使用call方法卓箫,foo使用的就是默認(rèn)綁定载矿,foo()輸出0,。使用call apply方法烹卒,輸出分別為1闷盔,2,3
- 什么是硬綁定:一種顯示綁定的變種
- 我們來看看這個(gè)顯式綁定變種到底是怎樣工作的甫题。我們創(chuàng)建了函數(shù) bar() ,并在它的內(nèi)部手動(dòng)調(diào)用了 foo.call(obj) ,因此強(qiáng)制把 foo 的 this 綁定到了 obj 馁筐。無論之后如何調(diào)用函數(shù) bar ,它總會(huì)手動(dòng),在 obj 上調(diào)用 foo 坠非。這種綁定是一種顯式的強(qiáng)制綁定敏沉,因此我們稱之為硬綁定。
var a =1;
function foo() {
console.log( this.a );
}
var obj = {
a:2
};
var obj_test = {
a:"test"
};
var bar = function() {
foo.call( obj );
};
bar(); //2
setTimeout( bar, 1000 ); // 2
bar.call( obj_test ); //2
硬綁定的bar不可能再修改它的this(指的是foo中的this),是不是解決了之前的隱式丟失炎码。(定時(shí)器內(nèi)部this的調(diào)用是獨(dú)立調(diào)用)
-簡(jiǎn)單的輔助綁定函數(shù)bind函數(shù)的作用:返回一個(gè)新的函數(shù)盟迟,并且指定該新函數(shù)的this指向
function bind(fn, obj) {
return function() {
return fn.apply( obj, arguments );
};
}
var obj = {
a:2
};
var obj_test = {
a:22
};
var bar = bind( foo, obj);
var b = bar(3); // 2 3 undefined
console.log( b ); // 5
bar.call(obj_test,3);//2 3 undefined
有了bind函數(shù),我們可以把經(jīng)過綁定的函數(shù)拿去使用(這樣它就有默認(rèn)值了)
new綁定
我們重新定義一下JS中的“構(gòu)造函數(shù)”潦闲。JavaScript攒菠,構(gòu)造函數(shù)只是一些使用 new 操作符時(shí)被調(diào)用的函數(shù)。它們并不會(huì)屬于某個(gè)類歉闰,也不會(huì)實(shí)例化一個(gè)類辖众。實(shí)際上,它們甚至都不能說是一種特殊的函數(shù)類型和敬,它們只是被 new 操作符調(diào)用的普通函數(shù)而已凹炸。
實(shí)際上并不存在所謂的“構(gòu)造函數(shù)”,只有對(duì)于函數(shù)的“構(gòu)造調(diào)用”
使用 new 來調(diào)用函數(shù)昼弟,或者說發(fā)生構(gòu)造函數(shù)調(diào)用時(shí)啤它,對(duì)于我們的this來說。這個(gè)新對(duì)象會(huì)綁定到函數(shù)調(diào)用的 this 舱痘。
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log( bar.a ); // 2
使用 new 來調(diào)用 foo(..) 時(shí)变骡,我們會(huì)構(gòu)造一個(gè)新對(duì)象并把它綁定到 foo(..) 調(diào)用中的 this 上。new 是最后一種可以影響函數(shù)調(diào)用時(shí) this 綁定行為的方法芭逝,我們稱之為 new 綁定塌碌。
綁定的優(yōu)先級(jí)
最后我們來說一說綁定的優(yōu)先級(jí)
new綁定 > 顯示綁定 > 隱式綁定 > 默認(rèn)綁定
綁定例外
es6中胖箭頭this指向與我們現(xiàn)在的規(guī)則不一樣
被忽略的this:apply call bind(null) this----> window
柯里化:為函數(shù)去預(yù)綁定參數(shù)
var obj = Object.create(null)
之后如果有機(jī)會(huì)我會(huì)在下面繼續(xù)補(bǔ)充的。铝耻。誊爹。蹬刷。