function關(guān)鍵字函數(shù)前提下
籠統(tǒng)的原則:非嚴(yán)格模式下,當(dāng)this用于函數(shù)內(nèi)部的時(shí)候恢准,this的指向在函數(shù)調(diào)用階段才確定钧椰,它永遠(yuǎn)指向調(diào)用函數(shù)的那個(gè)對(duì)象怨愤。
情形 | this指向 |
---|---|
由A元素觸發(fā)事件 | A元素 |
調(diào)用A對(duì)象內(nèi)的B方法寞缝,B方法內(nèi)有this | A對(duì)象 |
new A函數(shù)癌压,A函數(shù)內(nèi)有this | new出的對(duì)象 |
非嚴(yán)格模式,全局函數(shù)內(nèi)有this | window |
嚴(yán)格模式荆陆,全局函數(shù)內(nèi)有this | undefined |
延時(shí)函數(shù)(setTimeout等)內(nèi)有this | window |
箭頭函數(shù)前提下
原則:箭頭函數(shù)前提下滩届,this指向在任何前提下都只有唯一一種可能性。
情形 | this指向 |
---|---|
箭頭函數(shù)中的this | 箭頭函數(shù)所在作用域的上一級(jí)作用域中的this |
詳解
(一)this在全局作用域永遠(yuǎn)指向window
this.a = 1;
alert(window.a); // 1
(二)在全局環(huán)境運(yùn)行函數(shù)被啼,因?yàn)檎{(diào)用函數(shù)的是window帜消,所以this指向全局對(duì)象,即window
function test(){
this.x = 1;
}
test();
window.x; // 1浓体,說明this的確指向了window
嚴(yán)格模式下又有不同:
"use strict";
function test(){
this.x = 1;
}
test();
window.x; // Cannot set property 'x' of undefined(…)
嚴(yán)格模式這么做的用意是泡挺,禁止函數(shù)內(nèi)的this關(guān)鍵字指向全局對(duì)象,避免莫名其妙的錯(cuò)誤命浴。
(三)函數(shù)被賦值給對(duì)象的方法娄猫,則調(diào)用函數(shù)的是對(duì)象,所以this指向這個(gè)對(duì)象
function test(){
alert(this.a);
}
var o = {};
o.a = 1;
o.b = test;
o.b(); // 彈出1
function test(){
alert(this.a);
}
var a = 1; // 等同于window.a = 1
var o = test; // 等同于window.o = test;生闲,this指向window
o(); // 等同于window.o()媳溺,彈出1
(四)函數(shù)是構(gòu)造函數(shù)時(shí),new出的實(shí)例對(duì)象調(diào)用構(gòu)造函數(shù)碍讯,所以this指向new出的實(shí)例對(duì)象
function test(){
this.a = 1;
}
var o = new test();
console.log(o.a); // 1
(五)apply()用法悬蔽、call()用法以及bind()用法
函數(shù)對(duì)象的call()方法和apply()方法
apply()、call()的作用一句話說就是:傳入別的this冲茸,繼而改變this屯阀;后面的參數(shù)是贈(zèng)送的,可以不寫轴术。
下面這道題难衰,改變this指向不是目的,將數(shù)組作為一系列參數(shù)傳給Math.max
才是目的逗栽。
var numbers = [5, 6, 2, 3, 7, 11];
var max = Math.max.apply(null, numbers);
console.log(max);
怎么理解Math.max.apply(null, numbers)
盖袭?apply
做3件事:
傳入this指向,也就是傳入了null彼宠,這時(shí)候this指向
window
鳄虱。但其實(shí)這不是目的。numbers
雖然是數(shù)組凭峡,但是會(huì)被apply
拆成一個(gè)個(gè)參數(shù)傳給Math.max
拙已,因?yàn)?code>Math.max只接受一個(gè)個(gè)參數(shù)。執(zhí)行一次
Math.max
摧冀。
總結(jié)
以上五種綁定規(guī)則倍踪,去掉沒什么用的在全局作用域的this系宫,其他四種規(guī)則的使用先后推斷如下:
- 看函數(shù)是否在 new 中調(diào)用(new 綁定)?如果是的話 this 綁定的是新創(chuàng)建的對(duì)象(即
bar
)建车。
var bar = new foo();
- 看函數(shù)是否通過 call扩借、apply (顯式綁定)?如果是的話缤至,this 綁定的是指定的對(duì)象(即
obj2
)潮罪。
var bar = foo.call(obj2);
- 看函數(shù)是否在某個(gè)上下文對(duì)象中調(diào)用(隱式綁定)?如果是的話领斥,this 綁定的是那個(gè)上下文對(duì)象(即
obj1
)嫉到。
var bar = obj1.foo();
如果都不是的話,使用默認(rèn)綁定戒突。如果在嚴(yán)格模式下屯碴,就綁定到 undefined,否則綁定到全局對(duì)象膊存。
var bar = foo();
做面試題
參考別人寫的http://www.reibang.com/p/de47c2f9d178 吧导而。比我總結(jié)的牛逼,我個(gè)人非常喜歡這種應(yīng)試方式隔崎。
關(guān)于JavaScript函數(shù)執(zhí)行環(huán)境的過程今艺,IBM developerworks文檔庫(kù)中的一段描述感覺很不錯(cuò),摘抄如下:
“JavaScript 中的函數(shù)既可以被當(dāng)作普通函數(shù)執(zhí)行爵卒,也可以作為對(duì)象的方法執(zhí)行虚缎,這是導(dǎo)致 this 含義如此豐富的主要原因。一個(gè)函數(shù)被執(zhí)行時(shí)钓株,會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境(ExecutionContext)实牡,函數(shù)的所有的行為均發(fā)生在此執(zhí)行環(huán)境中,構(gòu)建該執(zhí)行環(huán)境時(shí)轴合,JavaScript 首先會(huì)創(chuàng)建 arguments變量创坞,其中包含調(diào)用函數(shù)時(shí)傳入的參數(shù)。接下來創(chuàng)建作用域鏈受葛。然后初始化變量题涨,首先初始化函數(shù)的形參表,值為 arguments變量中對(duì)應(yīng)的值总滩,如果 arguments變量中沒有對(duì)應(yīng)值纲堵,則該形參初始化為 undefined。如果該函數(shù)中含有內(nèi)部函數(shù)闰渔,則初始化這些內(nèi)部函數(shù)席函。如果沒有,繼續(xù)初始化該函數(shù)內(nèi)定義的局部變量冈涧,需要注意的是此時(shí)這些變量初始化為 undefined向挖,其賦值操作在執(zhí)行環(huán)境(ExecutionContext)創(chuàng)建成功后蝌以,函數(shù)執(zhí)行時(shí)才會(huì)執(zhí)行,這點(diǎn)對(duì)于我們理解 JavaScript 中的變量作用域非常重要何之。
鑒于篇幅,我們先不在這里討論這個(gè)話題咽筋。最后為 this變量賦值溶推,如前所述,會(huì)根據(jù)函數(shù)調(diào)用方式的不同奸攻,賦給 this全局對(duì)象蒜危,當(dāng)前對(duì)象等。至此函數(shù)的執(zhí)行環(huán)境(ExecutionContext)創(chuàng)建成功睹耐,函數(shù)開始逐行執(zhí)行辐赞,所需變量均從之前構(gòu)建好的執(zhí)行環(huán)境(ExecutionContext)中讀取∠跹担”
理解這段話對(duì)于理解Javascript函數(shù)將大有好處响委。