初學JS的朋友可能對this指向問題有些困惑昂拂。最近在看《Javascript設計模式與開發(fā)實踐》一書运授,里面總結得很到位咏尝。梳理下大致可以分為4情況,有興趣的可以自行去翻書閱讀褂傀。
作為對象的方法調(diào)用
作為普通函數(shù)調(diào)用
構造器調(diào)用
Function.prototype.call和Function.prototype.apply調(diào)用
1忍啤、作為對象的方法調(diào)用
當函數(shù)作為對象的方法被調(diào)用時,此時this指向該對象仙辟。
var obj = {
name: lq,
getName: function () {
console.log (this === obj); // true
console.log (this.name); // lq
}
}
2同波、作為普通函數(shù)調(diào)用
當函數(shù)不作為對象屬性被調(diào)用,而是通過普通的函數(shù)調(diào)用欺嗤,此時的this總是指向全局對象参萄。在瀏覽器環(huán)境的JavaScript里,就是window對象煎饼。
window.name = 'lq';
let getName = function () {
return this.name;
}
console.log ( getName() ); // 輸出:lq 此時this指向window對象
又比如:
window.name = 'lq';
let myObj = {
name: 'xiaoming',
getName: function () {
return this.name;
}
};
let getName = myObj.getName;
console.log ( getName() ); // 輸出:lq
有時候在我們點擊div節(jié)點的事件函數(shù)內(nèi)部讹挎,如果有一個callback回調(diào)函數(shù),當callback被當作普通函數(shù)調(diào)用時吆玖,callback內(nèi)部的this指向window,但實際上我們想讓它指向被點擊的div節(jié)點本身筒溃。代碼如下:
<html>
<body>
<div id='div1'>my is div node</div>
</body>
<script>
window.id = 'window';
document.querySelector('#div1').onclick = function () {
console.log (this.id); // 輸出:div1
let callback = function () {
console.log (this.id); // 輸出:window
}
callback();
}
</script>
</html>
通常的解決方法是用一個變量來保存div節(jié)點的引用:
document.querySelector('#div1').onclick = function () {
let _this = this;
let callback = function () {
console.log (_this.id); //輸出:div1
}
callback();
}
另外,在ESMAScript5下的strict嚴格模式下沾乘,這種普通函數(shù)調(diào)用已經(jīng)被規(guī)定為不會指向全局對象怜奖,而是undefined。
function fun () {
'use strict'
console.log (this); //輸出了:undefined
}
fun();
3翅阵、構造器調(diào)用
Javascript種沒有類的概念歪玲,但提供了new運算符迁央,這樣我們可以從構造器中創(chuàng)建對象。除了宿主提供的一些內(nèi)置函數(shù)滥崩,大部分的Javascript函數(shù)可以當作構造器使用岖圈。構造器跟普通函數(shù)沒什么太大區(qū)別,唯一的區(qū)別是被調(diào)用的方式钙皮。
當用new運算符調(diào)用函數(shù)時蜂科,該函數(shù)會返回一個對象,一般情況下短条,構造器里的this都指向返回的這個對象导匣。如下:
let myObj = function () {
this.name = 'lq';
};
let obj = new myObj();
console.log (obj.name); //輸出:lq
如果new構造器顯式地返回一個object類型的對象,那么運算的結果就會最終返回這個對象茸时,this就不是我們之前所期望的this了贡定。如下:
let myObj = function () {
this.name = 'lq';
return {
name: 'xiaoming';
}
}
let obj = new myObj();
console.log(obj.name); // 輸出:xiaoming
如果構造器返回的不是object類型的對象,而是一個非對象類型的數(shù)據(jù)屹蚊,就沒有上面的問題厕氨。
let myObj = function () {
this.name = 'lq';
return 'xiaoming';
};
let obj = new myObj();
console.log (obj.name); //輸出:lq
4、Function.prototype.call和Function.prototype.apply調(diào)用
這兩種方式調(diào)用可以動態(tài)地改變傳入函數(shù)的this:
let obj1 = {
name: 'lq',
getName: function () {
return this.name;
}
};
let obj2 = {
name: 'xiaoming'
};
console.log (obj1.getName()); //輸出:lq
console.log (obj1.getName.call(obj2)); // 輸出:xiaoming
console.log (obj1.getName.apply(obj2)); //輸出:xiaoming