What's this?
由于運(yùn)行期綁定的特性,JavaScript 中的 this 含義非常多,它可以是全局對(duì)象、當(dāng)前對(duì)象或者任意對(duì)象,這完全取決于函數(shù)的調(diào)用方式
隨著函數(shù)使用場(chǎng)合的不同,this的值會(huì)發(fā)生變化。但是有一個(gè)總的原則,那就是this指的是,調(diào)用函數(shù)的那個(gè)對(duì)象
作為函數(shù)調(diào)用
在函數(shù)被直接調(diào)用時(shí)this綁定到全局對(duì)象。在瀏覽器中,window 就是該全局對(duì)象
console.log(this);//window
function fn1(){
console.log(this);
}
fn1();//window 因?yàn)樵趂n的作用域里找不到,就會(huì)像上找,這樣就會(huì)找到window
還有,函數(shù)里this不是代表函數(shù)本身,這個(gè)很重要,很多新人都會(huì)犯這個(gè)錯(cuò)誤,包括我之前也老是覺(jué)得,函數(shù)里的this,代表的就是這個(gè)函數(shù),這是錯(cuò)誤的,下面我們來(lái)看這個(gè)例子
var a = 100
function fn(){
var a = 1
console.log(this.a);
}
fn()//100
很多新手一看就覺(jué)得,咦!怎么打印的不是1,而是全局下的a呢?因?yàn)樵诤瘮?shù)里找不到this,那么就會(huì)去外面找,上面說(shuō)了,外面的this代表window,所以console.log(this.a);實(shí)際上就是console.log(window.a);,所以打印出的值是100。
內(nèi)部函數(shù)
函數(shù)嵌套產(chǎn)生的內(nèi)部函數(shù)的this不是其父函數(shù),仍然是全局變量
function parent(){
function children(){
console.log(this);
}
children()
}
parent()//window
首先會(huì)再函數(shù)內(nèi)部找this,發(fā)現(xiàn)子函數(shù)里找不到this,那就去父函數(shù)找,還是找不到,最后就去父函數(shù)的外面也就是全局下找this,所以打印出的是window
setTimeout、setInterval
這兩個(gè)方法執(zhí)行的函數(shù)this也是全局對(duì)象
document.addEventListener('click', function(e){
console.log(this);
setTimeout(function(){
console.log(this);
}, 200);
}, false);
第一個(gè)this是綁定事件的這個(gè)元素,第二個(gè)this代表的全局對(duì)象window,如下圖所示

如果在函數(shù)里申明了var self=this,那么第二個(gè)this就變掉了,相當(dāng)于把第一個(gè)this代表的元素保存起來(lái)了,我們直接來(lái)看代碼。如果看的有點(diǎn)繞的話,可以這么想,我可以不用_this,可以用me、self來(lái)代替,效果一樣

document.addEventListener('click', function(e){
console.log(this);
var me = this
setTimeout(function(){
console.log(me);
}, 200);
}, false)
作為構(gòu)造函數(shù)調(diào)用
所謂構(gòu)造函數(shù),就是通過(guò)這個(gè)函數(shù)生成一個(gè)新對(duì)象(object)。這時(shí),this就指這個(gè)新對(duì)象
new 運(yùn)算符接受一個(gè)函數(shù) F 及其參數(shù):new F(arguments...)。這一過(guò)程分為三步:
- 創(chuàng)建類(lèi)的實(shí)例。這步是把一個(gè)空的對(duì)象的
__proto__屬性設(shè)置為 F.prototype 。 - 初始化實(shí)例。函數(shù) F 被傳入?yún)?shù)并調(diào)用,關(guān)鍵字 this 被設(shè)定為該實(shí)例。
- 返回實(shí)例。
function Person(name){
this.name = name;
}
Person.prototype.printName = function(){
console.log(this.name);
};
var p1 = new Person('Byron');
var p2 = new Person('Casper');
var p3 = new Person('Vincent');
p1.printName();
p2.printName();
p3.printName();
p1.printName();這句話執(zhí)行的時(shí)候,先執(zhí)行p1 = new Person('Byron'),然后在new的時(shí)候,做了三件事,
1、創(chuàng)建新的空對(duì)象
2、然后是把這個(gè)空的對(duì)象的 __proto__ 屬性設(shè)置為 Person.prototype
3、執(zhí)行函數(shù)Person,遇到this,就認(rèn)為this是剛才創(chuàng)建的對(duì)象,給它添加一個(gè)屬性name,而這個(gè)屬性的值就是函數(shù)Person的name
執(zhí)行完成之后,把新對(duì)象return出來(lái)賦值給p1
這樣就可以通過(guò)p1的方式去用了
作為對(duì)象方法調(diào)用
在 JavaScript 中,函數(shù)也是對(duì)象,因此函數(shù)可以作為一個(gè)對(duì)象的屬性,此時(shí)該函數(shù)被稱(chēng)為該對(duì)象的方法,在使用這種調(diào)用方式時(shí),this 被自然綁定到該對(duì)象,簡(jiǎn)單的來(lái)說(shuō),就是誰(shuí)調(diào)用這個(gè)函數(shù),這個(gè)函數(shù)指的就是誰(shuí)(這個(gè)this就代表誰(shuí))。
如:Object1.fn(),this指的就是Object1,
假如:Object1.Object2.Object3.fn(),this指的就是Object3,
this指向最后一次調(diào)用者
var obj1 = {
name: 'Byron',
fn : function(){
console.log(this);
}
};
obj1.fn();//{name: "Byron", fn: ?}
var fn2 = obj1.fn;
fn2();//window 因?yàn)閒n是全局變量,等同于執(zhí)行winow.fn2()