相信大家都有看過(guò)這樣的一道javascript的面試題雾叭,具體如下:
var length = 10;
function fn(){
console.log(this.length);
}
var obj = {
length:5,
method:function(fn){
fn();
arguments[0]();
}
}
obj.method(fn,1);
這道題主要考察的是this的指向和arguments對(duì)象悟耘,第二個(gè)輸出為2,這里我們不討論這個(gè)話題织狐。第一個(gè)輸出的如果對(duì)this理解模糊的話容易答出5的答案暂幼,其實(shí)答案為10。
分析:javascript判斷this綁定的判定規(guī)則是調(diào)用位置是否有上下文對(duì)象移迫,或者說(shuō)是否被某個(gè)對(duì)象擁有或者包含旺嬉,先思考如下代碼:
function fn(){
console.log(this.a);
}
var obj = {
a:2,
fn:fn
}
obj.fn(); //2
首先需要注意的是fn()的聲明方式,及其之后是如何被當(dāng)作引用屬性添加到obj中的厨埋。但是無(wú)論是直接在obj定義還是先定義再添加為引用屬性邪媳,這個(gè)函數(shù)嚴(yán)格來(lái)說(shuō)都不屬于obj對(duì)象。
然而荡陷,調(diào)用位置會(huì)使用obj的上下文來(lái)引用函數(shù)雨效,因此你可以說(shuō)函數(shù)被調(diào)用時(shí)obj對(duì)象“擁有”或者“包含”它。
無(wú)論你如何稱呼這個(gè)模式废赞,但fn()被調(diào)用時(shí)徽龟,它的前面確實(shí)加上了對(duì)obj的引用。當(dāng)函數(shù)引用有上下文對(duì)象時(shí)唉地,函數(shù)調(diào)用中的this會(huì)綁定到這個(gè)上下文對(duì)象据悔。因此調(diào)用fn()時(shí)this被綁定到obj,因此this.a和obj.a時(shí)一樣的耘沼。
一種最常見(jiàn)的this綁定問(wèn)題就是被隱式綁定的函數(shù)會(huì)丟失綁定對(duì)象极颓,也就是說(shuō)它會(huì)應(yīng)用默認(rèn)綁定,從而把this綁定到全局對(duì)象或者undefined上群嗤。
思考下面的代碼:
function fn(){
console.log(this.a);
}
var obj = {
a:2,
fn:fn
}
var bar = obj.fn; //函數(shù)別名
bar();//undefined
雖然bar是obj.fn的一個(gè)引用菠隆,但是實(shí)際上,它引用的是fn函數(shù)本身,因此此時(shí)的bar()其實(shí)是一個(gè)不帶任何修飾的函數(shù)調(diào)用浸赫,因此為undefined闰围。
回到之前的筆試題,參數(shù)傳遞其實(shí)就是一種隱式的賦值既峡,下面的例子的參數(shù)傳遞和上面例子的 var bar = obj.fn其實(shí)是一樣的羡榴。所以答案為10。
var length = 10;
function fn(){
console.log(this.length);
}
var obj = {
length:5,
method:function(fn){//fn其實(shí)引用的是function fn()
fn();//這里才是真正的調(diào)用位置
arguments[0]();
}
}
obj.method(fn,1);
那如果把函數(shù)傳入到語(yǔ)言內(nèi)置的函數(shù)而不是傳入你自己聲明的函數(shù)运敢,會(huì)發(fā)生什么呢校仑?結(jié)果是一樣的,沒(méi)有區(qū)別:
function fn(){
console.log(this.a);
}
var obj = {
a:2,
fn:fn
}
var a = "global";
setTimeout(obj.fn,100);
javascript環(huán)境中內(nèi)置的setTimeout()函數(shù)的實(shí)現(xiàn)和下面的偽代碼類似:
function setTimeout(fn,delay){
//等待delay毫秒
fn();//調(diào)用位置
}
就像我們看到的那樣传惠,回調(diào)函數(shù)丟失this綁定是很常見(jiàn)的迄沫。除此之外,還有一種情況this的行為出乎我們的意料:調(diào)用回調(diào)函數(shù)的函數(shù)可能會(huì)修改this卦方。在一些流行的javascript框架中的事件處理器常會(huì)把回調(diào)函數(shù)的this強(qiáng)制綁定到觸發(fā)事件的dom元素上羊瘩。最后來(lái)一道測(cè)試題:
function fn(){
console.log(this.a);
}
var a = 2;
var o = { a:3,fn:fn};
var p = { a:4}
o.fn();//輸出?
(p.fn = o.fn)();//輸出盼砍?
答案:3和2尘吗。
最后,分享下分析這種隱式綁定的原則:如果在一個(gè)對(duì)象內(nèi)包含一個(gè)指向函數(shù)的屬性浇坐,并通過(guò)這個(gè)屬性間接引用函數(shù)睬捶,只有在這種情況下的this才會(huì)綁定到這個(gè)對(duì)象上。