前言
學(xué)習(xí)js
也快有一段時(shí)間了,一直不怎么想碰this
,也碰到別人寫(xiě)的一些關(guān)于this
,一直懶得看,但是最近在學(xué)習(xí)DOM事件,寫(xiě)代碼中經(jīng)城@玻看見(jiàn)this
,有時(shí)候理解的不太透徹,所以決定把它研究一下,當(dāng)然了,現(xiàn)在寫(xiě)的this
也只是我現(xiàn)在的水平和參考一下大神的文章,自己結(jié)合起來(lái),寫(xiě)給自己的
正文:
引自 MDN this
- 與其他語(yǔ)言相比品洛,函數(shù)的 this關(guān)鍵字在JavaScript中的表現(xiàn)略有不同,此外,在嚴(yán)格模式和非嚴(yán)格模式之間也會(huì)有一些差別。
- 在絕大多數(shù)情況下,函數(shù)的調(diào)用方式?jīng)Q定了this的值瘫怜。this不能在執(zhí)行期間被賦值,并且在每次函數(shù)被調(diào)用時(shí)this的值也可能會(huì)不同本刽。ES5引入了bind方法來(lái)設(shè)置函數(shù)的this值鲸湃,而不用考慮函數(shù)如何被調(diào)用的,ES2015引入了支持this詞法解析的箭頭函數(shù)(它在閉合的執(zhí)行上下文內(nèi)設(shè)置this
的值)子寓。
什么是this?
this
是在執(zhí)行上下文創(chuàng)建時(shí)確定的一個(gè)在執(zhí)行過(guò)程中不可更改的變量暗挑。
- 所謂執(zhí)行上下文,就是JavaScript引擎在執(zhí)行一段代碼之前將代碼內(nèi)部會(huì)用到的一些變量斜友、函數(shù)炸裆、this提前聲明然后保存在變量對(duì)象中的過(guò)程。這個(gè)’代碼片段’包括:全局代碼(script標(biāo)簽內(nèi)部的代碼)鲜屏、函數(shù)內(nèi)部代碼烹看、eval內(nèi)部代碼。而我們所熟知的作用域鏈也會(huì)在保存在這里洛史,以一個(gè)類(lèi)數(shù)組的形式存儲(chǔ)在對(duì)應(yīng)函數(shù)的[[Scopes]]屬性中惯殊。
正文說(shuō):嚴(yán)格模式與飛非嚴(yán)格模式會(huì)有區(qū)別,我們來(lái)看一下:
看一下嚴(yán)格模式下
var a = 1;
function fun() {
'use strict';
var a = 2;
return this.a;
}
fun(); //報(bào)錯(cuò): Cannot read property 'a' of undefined
非嚴(yán)格模式下:
var a = 1;
function fun() {
var a = 2;
return this.a;
}
fun(); // 輸出 1
總結(jié): 當(dāng)函數(shù)獨(dú)立調(diào)用的時(shí)候,在嚴(yán)格模式下它的this指向undefined也殖,
在非嚴(yán)格模式下土思,當(dāng)this指向undefined的時(shí)候,自動(dòng)指向全局對(duì)象(瀏覽器中就是window)
正文說(shuō):絕大多數(shù)情況下,函數(shù)的調(diào)用方式?jīng)Q定了this的值
我們來(lái)看看函數(shù)有幾種調(diào)用方式
-
函數(shù)調(diào)用模式:
函數(shù)名()
- 方法調(diào)用模式
-
構(gòu)造函數(shù)調(diào)用模式
new Function(...)
-
apply(call)
調(diào)用模式
函數(shù)調(diào)用模式
//例子:
function add(i,j){
console.log(this); //Window
// console.log(arguments);
var sum = i+j;
console.log(sum);
(function(){
console.log(this); //Window
})()
return sum;
}
add(1,2);
從上面的例子我們看到this
兩次返回的都是window
全局對(duì)象,匿名函數(shù)也會(huì)產(chǎn)生本地作用域,打印也是window
按理說(shuō)第一次打印應(yīng)該是undefined
,但是瀏覽器里有一條規(guī)則:
如果你傳的 context 就 null 或者 undefined己儒,那么 window 對(duì)象就是默認(rèn)的 context(嚴(yán)格模式下默認(rèn) context 是 undefined)
總結(jié):函數(shù)調(diào)用模式this指向window的全局對(duì)象
方法調(diào)用模式
//例子:
var myNumber = {
value: 1,
add: function(i){
console.log(this); //Object{value: 1, add: ?}
this.value += i;
}
}
myNumber.add(1);
函數(shù)實(shí)現(xiàn)改變value的值加1,add被調(diào)用時(shí),this
的指向是Object對(duì)象
總結(jié):方法調(diào)用模式this指向調(diào)用者
構(gòu)造函數(shù)調(diào)用模式
//例子:
function Car(type,color){
this.type = type;
this.color = color;
this.status = "stop";
this.light = "off";
console.log(this); //打印結(jié)果是我們創(chuàng)建的對(duì)象
}
Car.prototype.start = function(){
this.status = "driving";
this.light = "on";
console.log(this.type + " is " + this.status);
}
Car.prototype.stop = function(){
this.status = "stop";
this.light = "off";
console.log(this.type + " is " + this.status);
}
var benz = new Car("benz", "black"); //Car {type: "benz", color: "black", status: "stop", light: "off"}
如果函數(shù)作為構(gòu)造函數(shù)用崎岂,那么其中的this就代表它即將new出來(lái)的對(duì)象
。為啥呢址愿?new做了啥呢该镣?new做了下面這些事:
- 創(chuàng)建一個(gè)臨時(shí)對(duì)象
- 給臨時(shí)對(duì)象綁定原型
- 給臨時(shí)對(duì)象對(duì)應(yīng)屬性賦值
- 將臨時(shí)對(duì)象return
也就是說(shuō)new其實(shí)就是個(gè)語(yǔ)法糖冻璃,this之所以指向臨時(shí)對(duì)象還是沒(méi)逃脫上面說(shuō)的幾種情況响谓。
總結(jié):構(gòu)造函數(shù)調(diào)用模式this指向被構(gòu)造的對(duì)象
apply(call)調(diào)用模式
- this指向第一個(gè)參數(shù)
對(duì)于這一個(gè),由于自己還沒(méi)學(xué)到,先借鑒MDN上的,后面自己再總結(jié)一下
如果要想把this的值從一個(gè)context傳到另一個(gè),就要用call省艳,或者apply
方法娘纷。
// 一個(gè)對(duì)象可以作為call和apply的第一個(gè)參數(shù),并且this會(huì)被綁定到這個(gè)對(duì)象跋炕。
var obj = {a: 'Custom'};
// 這個(gè)屬性是在global對(duì)象定義的赖晶。
var a = 'Global';
function whatsThis(arg) {
return this.a; // this的值取決于函數(shù)的調(diào)用方式
}
whatsThis(); // 直接調(diào)用, 返回'Global'
whatsThis.call(obj); // 通過(guò)call調(diào)用辐烂, 返回'Custom'
whatsThis.apply(obj); // 通過(guò)apply調(diào)用 遏插,返回'Custom'
當(dāng)一個(gè)函數(shù)的函數(shù)體中使用了this關(guān)鍵字時(shí),通過(guò)call()方法和apply()方法調(diào)用纠修,this的值可以綁定到一個(gè)指定的對(duì)象上胳嘲。call()和apply()的所有函數(shù)都繼承自Function.prototype 。
function add(c, d) {
return this.a + this.b + c + d;
}
var o = {a: 1, b: 3};
// 第一個(gè)參數(shù)是作為‘this’使用的對(duì)象
// 后續(xù)參數(shù)作為參數(shù)傳遞給函數(shù)調(diào)用
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
// 第一個(gè)參數(shù)也是作為‘this’使用的對(duì)象
// 第二個(gè)參數(shù)是一個(gè)數(shù)組扣草,數(shù)組里的元素用作函數(shù)調(diào)用中的參數(shù)
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
使用 call 和 apply 函數(shù)的時(shí)候要注意了牛,如果傳遞的 this 值不是一個(gè)對(duì)象,JavaScript 將會(huì)嘗試使用內(nèi)部 ToObject 操作將其轉(zhuǎn)換為對(duì)象辰妙。因此鹰祸,如果傳遞的值是一個(gè)原始值比如 7 或 'foo' ,那么就會(huì)使用相關(guān)構(gòu)造函數(shù)將它轉(zhuǎn)換為對(duì)象密浑,所以原始值 7 通過(guò)new Number(7)被轉(zhuǎn)換為對(duì)象蛙婴,而字符串'foo'使用 new String('foo') 轉(zhuǎn)化為對(duì)象,例如:
function bar() {
console.log(Object.prototype.toString.call(this));
}
//原始值 7 被隱式轉(zhuǎn)換為對(duì)象
bar.call(7); // [object Number]
參考資料