注意:誰調用它男杈,this就指向誰
全局執(zhí)行
- 瀏覽器
console.log(this);
// Window {speechSynthesis: SpeechSynthesis, caches: CacheStorage, localStorage: Storage, sessionStorage: Storage, webkitStorageInfo: DeprecatedStorageInfo…}
打印出來了window
對象。
- Node
console.log(this);
// global
- 總結:在全局作用域中它的
this
執(zhí)行當前的全局對象(瀏覽器端是Window
旺垒,node 中是global
)肤无。
函數(shù)執(zhí)行
- 純粹的函數(shù)調用
最普通的函數(shù)使用方法:
function test() {
console.log(this);
};
test();
// Window {speechSynthesis: SpeechSynthesis, caches: CacheStorage, localStorage: Storage, sessionStorage: Storage, webkitStorageInfo: DeprecatedStorageInfo…}
我們可以看到,一個函數(shù)被直接調用的時候竞漾,屬于全局調用业岁,這時候它的 this
指向 全局對象;
- 嚴格模式: 'use strict'
如果在嚴格模式的情況下執(zhí)行純粹的函數(shù)調用棍好,那么這里的的this
并不會指向全局借笙,而是undefined
业稼,這樣的做法是為了消除 js 中一些不嚴謹?shù)男袨椋?/li>
use strict';
function test() {
console.log(this);
};
test();
// undefined
當然念链,把它放在一個立即執(zhí)行函數(shù)中會更好,避免了污染全局:
(function (){
"use strict";
console.log(this);
})();
// undefined
作為對象的方法調用
當一個函數(shù)被當作一個對象的方法調用的時候:
var obj = {
name: 'qiutc',
foo: function() {
console.log(this.name);
}
}
obj.foo();
// 'qiutc'
這時候谦纱,this
指向當前的這個對象跨嘉;
如果把對象的方法賦值給一個變量祠乃,然后直接調用這個變量呢:
var obj = {
name: 'qiutc',
foo: function() {
console.log(this);
}
}
var test = obj.foo;
test();
// Window
可以看到兑燥,這時候 this
執(zhí)行了全局,當我們把 test = obj.foo
嘱支,text
直接把等號右邊當做一個函數(shù)挣饥,并不管什么obj
扔枫。test
直接指向了一個函數(shù)的引用短荐,這時候叹哭,其實和 obj
這個對象沒有關系了话速,所以泊交,它是被當作一個普通函數(shù)來直接調用廓俭,因此,this
指向全局對象。重點淋硝。
經(jīng)典例子
var obj = {
name: 'qiutc',
foo: function() {
console.log(this); //直接打印出obj整個對象
},
foo2: function() {
console.log(this); //打印出整個obj對象
var _this = this;
setTimeout(function() {
console.log(this); // Window
console.log(_this); // Object {name: "qiutc"}
}, 1000);
}
}
obj.foo2();
obj.foo();
- 首先竿报,因為
誰調用this烈菌,this就指向誰
,所以花履,foo和foo2里面的console.log(this)
直接指向調用他們的obj對象诡壁,打印出Obj整個對象妹卿。 - 然后纽帖,在看
setTimeout
里面的懊直。在外面雕崩,var _this = this;
這個this
是指向obj的(上面已經(jīng)打印出來了)融撞。用一個變量_this
來儲存尝偎。所以console.log(_this);
可以打印出obj對象致扯。因為我們已經(jīng)用_this來指向obj對象了抖僵,所以console.log(this); // Window
耍群。this只能指向全局了蹈垢。 - 還有一點就是在foo2作用域內非setTimeout作用域內
console.log(this);
發(fā)現(xiàn)打印出obj對象曹抬。console.log(_this);
也是這樣。說明setTimeout
塊級作用域隔絕了foo2
作用域的滲透。
作為一個構造函數(shù)使用
在 js 中赖临,為了實現(xiàn)類兢榨,我們需要定義一些構造函數(shù)吵聪,在調用一個構造函數(shù)的時候需要加上 new
這個關鍵字:
function Person(name) {
this.name = name;
console.log(this);
}
var p = new Person('qiutc');
// Person {name: "qiutc"}
我們可以看到當作構造函數(shù)調用時吟逝,this
指向了這個構造函數(shù)調用時候實例化出來的對象块攒;
當然佃乘,構造函數(shù)其實也是一個函數(shù)趣避,如果我們把它當作一個普通函數(shù)執(zhí)行程帕,這個 this
仍然執(zhí)行全局:
function Person(name) {
this.name = name;
console.log(this);
}
var p = Person('qiutc');
// Window
其區(qū)別在于骆捧,如何調用函數(shù)(new
)
箭頭函數(shù)
在 ES6 的新規(guī)范中敛苇,加入了箭頭函數(shù)顺呕,它和普通函數(shù)最不一樣的一點就是 this
的指向了株茶。用閉包來解決 this
的指向問題,用上了箭頭函數(shù)就可以更完美的解決。
var obj = {
name: 'qiutc',
foo: function() {
console.log(this);
},
foo2: function() {
console.log(this);
setTimeout(() => {
console.log(this); // Object {name: "qiutc"}
}, 1000);
}
}
obj.foo2();
可以看到卧抗,在 setTimeout
執(zhí)行的函數(shù)中社裆,本應該打印出在 Window
泳秀,但是在這里 this
卻指向了 obj
嗜傅,原因就在于檩赢,給 setTimeout
傳入的函數(shù)(參數(shù))是一個箭頭函數(shù):
箭頭函數(shù)體內的this對象,就是定義時所在的對象憔狞,而不是使用時所在的對象瘾敢。
根據(jù)例子我們理解一下這句話:
在 obj.foo2()
執(zhí)行的時候簇抵,當前的 this
指向 obj
;在執(zhí)行 setTimeout
時候晃财,我們先是定義了一個匿名的箭頭函數(shù),關鍵點就在這愉舔,箭頭函數(shù)內的 this
執(zhí)行定義時所在的對象轩缤,就是指向定義這個箭頭函數(shù)時作用域內的 this
火的,也就是 obj.foo2
中的 this
馏鹤,即 obj
假瞬;所以在執(zhí)行箭頭函數(shù)的時候脱茉,它的 this
-> obj.foo2 中的 this
-> obj
琴许;
簡單來說, 箭頭函數(shù)中的 this 只和定義它時候的作用域的 this 有關益兄,而與在哪里以及如何調用它無關净捅,同時它的 this 指向是不可改變的荆永。這個箭頭函數(shù)在foo2
的作用域下具钥,所以就指向foo2
液兽。
所以對于箭頭函數(shù)四啰,只要看它在哪里創(chuàng)建的就行拟逮。