作為一個(gè)前端學(xué)習(xí)者,在學(xué)習(xí)之路上總會(huì)遇到一些難題,突發(fā)奇想,便隨手記錄一下。
關(guān)于this
this作為javascript常用的關(guān)鍵字之一,被人們稱(chēng)為最復(fù)雜的機(jī)制之一,他就像一個(gè)魔術(shù)師,變幻著令人著迷的戲法,來(lái)混淆你的視聽(tīng)。而作為觀眾的我們?cè)谛蕾p完這眼花繚亂的魔術(shù)之后,總想了解一下背后的秘密。
理解this的指向
在js中,函數(shù)的幾種調(diào)用方式有:
普通函數(shù)調(diào)用
作為對(duì)象方法來(lái)調(diào)用
作為構(gòu)造函數(shù)來(lái)調(diào)用
使用apply/call方法來(lái)調(diào)用
this是在運(yùn)行時(shí)進(jìn)行綁定的,它的上下文取決于函數(shù)調(diào)用時(shí)的各種條件,this的綁定和函數(shù)聲明的位置沒(méi)有任何關(guān)系,只取決于函數(shù)的調(diào)用方式。
簡(jiǎn)單來(lái)說(shuō):this的最終指向的是那個(gè)調(diào)用它的對(duì)象(誰(shuí)調(diào)用這個(gè)函數(shù)或者方法,this就指向誰(shuí))
普通函數(shù)調(diào)用
function foo(){
this.x = 1;
console.log(this.x);
console.log(this);
}
foo(); // 1 window
在這段代碼中foo是直接使用了不帶任何修飾的函數(shù)引用進(jìn)行調(diào)用的,所以使用了默認(rèn)綁定,即作為全局對(duì)象window的方法來(lái)進(jìn)行調(diào)用的,可以看作window.foo();所以這里是window對(duì)象調(diào)用了foo這個(gè)方法,也就是說(shuō)foo函數(shù)當(dāng)中的this是指向window,同時(shí)window還具有了一個(gè)屬性x,值為1。
var x = 1;
function foo(){
console.log(this.x);
}
foo(); // 1
這里為了證明this是全局變量,進(jìn)行了一下小改變。一開(kāi)始定義的全局變量x作為window的屬性,在調(diào)用時(shí),this肯定是指向全局對(duì)象window。
但是在嚴(yán)格模式下,則不能將全局對(duì)象用于默認(rèn)綁定,因此this會(huì)綁定到undefined。
function foo(){
"use strict";
console.log(this.x);
}
var x = 1;
foo(); // Uncaught TypeError: Cannot read property 'x' of undefined
雖然this的綁定規(guī)則完全取決于調(diào)用位置,但是只有foo()運(yùn)行在非嚴(yán)格模式下時(shí),默認(rèn)綁定才能綁定到全局對(duì)象。
作為對(duì)象方法的調(diào)用
var obj = {
x : "1",
foo: function() {
console.log(this.x);
}
};
obj.foo(); // 1
這里的this指向的是對(duì)象obj,因?yàn)槟阏{(diào)用這個(gè)foo是通過(guò)obj.foo()執(zhí)行的,那this就指向就是對(duì)象obj。再次強(qiáng)調(diào),this的綁定和函數(shù)聲明的位置沒(méi)有任何關(guān)系,只取決于函數(shù)的調(diào)用方式,誰(shuí)調(diào)用的就指向誰(shuí),這個(gè)很重要。
作為構(gòu)造函數(shù)來(lái)調(diào)用
function foo(){
this.x = 1;
}
var obj = new foo();
console.log(obj.x); // 1
這里可以實(shí)現(xiàn)輸出1是因?yàn)閚ew關(guān)鍵字可以改變this的指向,將this指向了obj對(duì)象。在傳統(tǒng)的面向類(lèi)語(yǔ)言中的new與js的new機(jī)制有著很多不同。在js中,構(gòu)造函數(shù)只是使用new操作符時(shí)被調(diào)用的函數(shù),不屬于某個(gè)類(lèi),也不會(huì)實(shí)例化一個(gè)類(lèi),只是被new操作符調(diào)用的普通函數(shù)。new是可以影響函數(shù)調(diào)用時(shí)this綁定行為的方法,稱(chēng)之為new綁定。
使用apply/call方法來(lái)調(diào)用
function foo(){
console.log(obj.x);
}
var obj = {
x:2
};
foo.call(obj); // 2
通過(guò)foo.call(),調(diào)用foo時(shí)將this綁定在了obj上。從this綁定的角度上,call()和apply()是一樣的。如果你把null或者undefined作為this綁定的對(duì)象傳入call,apply或者bind,在調(diào)用時(shí)會(huì)被忽略,執(zhí)行的是默認(rèn)綁定規(guī)則。
最后
如果要判斷一個(gè)運(yùn)行中的函數(shù)的this指向,就需要找到這個(gè)函數(shù)直接調(diào)用的位置。即誰(shuí)調(diào)用這個(gè)函數(shù)或者方法,this就指向誰(shuí)。
this雖然只是js里的一小部分,對(duì)于我們學(xué)習(xí)者而言還是很重要的。this還有很多奧秘等著我們?nèi)グl(fā)掘,我也只是知曉了其冰山一角,希望能分享一點(diǎn)自己的想法給一起學(xué)習(xí)路上的同學(xué)們,與君共勉。
參考
- 《你不知道的javascript》
- Javascript的this用法