作為一個剛?cè)腴TJavaScript小白,看了不少博客提到this慷荔,尤其是提到this的指向是動態(tài)的笛辟,隨著函數(shù)的調(diào)用會改變烙荷,以及牽扯到了作用域的一些問題,還可以手動去指定或者更改this的指向等等阳液。霉翔。似乎沒那么簡單,就不明覺厲柒凉,感覺必須得花時間探究一下了族阅。
從最簡單的打印說起:
// 全局打印
console.log(this); // [object Window]
// 但是在嚴(yán)格模式下this會指向undefined
'use strict';
console.log(this); // undefined
為了方便,以下的討論是在非嚴(yán)格模式下的情況膝捞,即全局打印this === Window
分以下幾個專題討論:
var = {...}對象內(nèi)部的this
var person = {
name: 'chengxuyuan',
age: 26,
eat: function() {
alert(this.name + '吃飯');
}
};
console.log(person.eat); // chengxuyuan吃飯
eat方法是person找個對象調(diào)用的坦刀,因此函數(shù)內(nèi)部使用的this就指向了person。為了更加嚴(yán)謹(jǐn)?shù)倪M(jìn)行論證,我們把層級弄的深一些:
var person = {
name: 'chengxuyuan',
age: 26,
eat: function() {
alert(this.name + '吃飯');
},
book: {
name: 'one day left',
show: function() {
alert(this.name + ' Good!');
}
}
};
console.log(person.book.show); // one day left Good
調(diào)用了person的book屬性的show方法鲤遥,this指向了book沐寺,this.name 就等于one day left。
因此盖奈,函數(shù)內(nèi)部this的值是跟它的調(diào)用者對象相關(guān)聯(lián)的混坞。
那如果某個函數(shù)是直接調(diào)用,而非xx.fun()的情況下钢坦,內(nèi)部的this又會怎么指向呢究孕?繼續(xù)上代碼:
var person = {
name: 'chengxuyuan',
age: 26,
play: function(){
function swim(){
console.log(this);
alert(this.name + '游泳');
}
swim();
}
};
console.log(person.play); // [object Window] undefined游泳
發(fā)現(xiàn)swim函數(shù)內(nèi)部的this指向了Window對象,因而this.name是undefined的爹凹。
特殊之處就是person對象調(diào)用play函數(shù)執(zhí)行的時候厨诸,內(nèi)部定義完swim函數(shù),緊接著就主動執(zhí)行了逛万。
而就是swim這個主動執(zhí)行的函數(shù)泳猬,內(nèi)部的this已經(jīng)跳出了person對象的勢力范圍,
因?yàn)閟wim函數(shù)主動執(zhí)行的時候宇植,調(diào)用它的對象是隱晦的得封,跟沒爹沒媽管似的,所以它內(nèi)部的this不指向person指郁,但也不能真讓他沒爹媽忙上,還是最后交給全局對象Window來管了。
構(gòu)造函數(shù)對象內(nèi)部的this
構(gòu)造函數(shù)利用''new + 方法名''的方式創(chuàng)建對象闲坎,它內(nèi)部的this指向也是差不多的原理:
function Person() {
console.log(this);
this.name = 'chengxuyuan';
this.age = 26;
console.log(this.name);
}
Person(); // [object Window] undefined
var p = new Person(); // [object Object] chengxuyuan
可以看出當(dāng)我們單純的直接調(diào)用執(zhí)行Person()函數(shù)疫粥,this指向Window
而我們通過new來創(chuàng)建出對象p的時候,this指向了person這個對象腰懂,因?yàn)榇蛴his.name為chengxuyuan梗逮。
還有一點(diǎn)要注意,通過prototype屬性定義函數(shù)的時候內(nèi)部的this也是指向Person的:
Person.prototype.getName = function() {
console.log(this.name);
}
var p = new Person();
p.getName(); // chengxuyuan
通過將函數(shù)賦值給其他變量,對內(nèi)部的this的指向的影響
function Person() {
this.name = 'chengxuyuan';
this.age = 26;
this.eat = function() {
alert(this.name + ' 吃飯');
}
}
var p = new Person();
var eatFunc = p.eat;
eatFunc(); // undefined 吃飯
看到清晰的認(rèn)識到eat原來屬于p绣溜,但是后來指向了全局對象eatFunc慷彤,因此eat內(nèi)部的this又動態(tài)的指向了Window。
學(xué)習(xí)到這里怖喻,就可以做一個小總結(jié)了底哗,函數(shù)內(nèi)部的this指向不是在定義的時候確定的,是被調(diào)用的時候锚沸,根據(jù)上下文場景跋选,動態(tài)的確定的。而且一般情況下都會指向調(diào)用它的對象哗蜈。**注意前标,是一般情況坠韩。可以接下來看看函數(shù)返回值對this的影響候生。
函數(shù)返回值對this的指向的影響
直接上代碼看幾個小例子:
function Person() {
this.name = 'chengxuyuan';
return {};
}
var p = new Person();
console.log(p.name); //undefined
當(dāng)構(gòu)造函數(shù)返回值是空對象的時候同眯,this不指向Person绽昼。
function Person() {
this.name = 'chengxuyuan';
return function() {};
}
var p = new Person();
console.log(p.name); //undefined
當(dāng)構(gòu)造函數(shù)返回值是空函數(shù)的時候唯鸭,this不指向Person。
function Person() {
this.name = 'chengxuyuan';
return undefined;
}
var p = new Person();
console.log(p.name); //chengxuyuan
當(dāng)構(gòu)造函數(shù)返回值是undefined的時候硅确,this竟然又指向Person目溉。
function Person() {
this.name = 'chengxuyuan';
return 1;
}
var p = new Person();
console.log(p.name); //chengxuyuan
當(dāng)構(gòu)造函數(shù)返回值是數(shù)值1的時候,this竟然又指向Person菱农。
function Person() {
this.name = 'chengxuyuan';
return null;
}
var p = new Person();
console.log(p.name); //chengxuyuan
當(dāng)構(gòu)造函數(shù)返回值是null的時候缭付,this竟然又指向Person。
總結(jié)一下吧:
當(dāng)構(gòu)造函數(shù)返回值為對象循未,函數(shù)的時候陷猫,this指向返回的具體對象函數(shù),當(dāng)為null或者其他值的時候的妖,this又會指向其所在的對象绣檬。
用call,apply,bind函數(shù)修改this的指向
有些業(yè)務(wù)場景下,有可能會涉及到想要修改this的指向嫂粟,那就可以利用call,apply,bind這三個函數(shù).
還是上面的一個通過將函數(shù)賦值給其他變量娇未,對內(nèi)部的this的指向的影響的例子:
function Person() {
this.name = 'chengxuyuan';
this.age = 26;
this.eat = function() {
alert(this.name + ' 吃飯');
}
}
var p = new Person();
var eatFunc = p.eat;
eatFunc(); // undefined 吃飯
已經(jīng)經(jīng)過由于eat函數(shù)賦值給了eatFunc,this指向了Window星虹。那如果非要讓this就指向p零抬。看下面怎么做:
call函數(shù):
var eatFunc = p.eat;
eatFunc.call(p); // chengxuyuan 吃飯
這下this又重新指向了p宽涌。
如果在更改this指向的時候平夜,還能傳一些其他參數(shù)到eat函數(shù)里面,還可以
function Person() {
this.name = 'chengxuyuan';
this.age = 26;
this.eat = function(a卸亮,b) {
alert('a + b =' + a + b);
alert(this.name + ' 吃飯');
}
}
var p = new Person();
var eatFunc = p.eat;
eatFunc.call(1,2); // a+b=3 chengxuyuan 吃飯
apply函數(shù):
apply函數(shù)也玩法一樣忽妒,主不過需要傳多個參數(shù)的時候,是通過參數(shù)數(shù)組接收的:
var eatFunc = p.eat;
eatFunc.apply(p嫡良,[1,2]); // a+b=3 chengxuyuan 吃飯
bind函數(shù):
apply函數(shù)也是用于修改this指向锰扶,但最大的不同是他的返回值是返回一個新的函數(shù)讓使用者接收:
var eatFunc = p.eat;
var bindfunc = eatFunc.bind(p);
bindfunc(); // chengxuyuan 吃飯
this在匿名函數(shù)以及箭頭函數(shù)中引起的作用域問題
后續(xù)補(bǔ)充。