對於程序員來說,this這個關鍵字應該是再熟悉不過了,在C++、C#以及Java中,它的身影隨處可見,this也可以說是編程語言JavaScript的精髓,但是一定也有不少JavaScript開發者都遇到過this的陷阱。
在C++、C#、Java中,this擁有十分明確的含義,就是單純指向當前的對象實例,但是,在動態編程語言JavaScript中,相同的this寫法,卻有不同的含義。
JavaScript中的this代表函數運行時自動生成的一個內部對象,只能在函數內部使用。並且,你不能在創建統計this的時候就確定它,而應該在函數執行時進行確定,所以,一不留神,你就會掉進意想不到的坑!
0、誰調用了就誰來負責
我們先來看看代碼:
var name = 'a';
var obj = {
name: 'b',
getName: function() {
console.log(this.name);
}
};
obj.getName(); // b
var getName = obj.getName;
getName(); // a
var obj2 = (function() {
return function() {
console.log(this.name);
}
})();
obj2(); // a
首先,obj.getName()打印出來b,因為,obj調用了getName(),所以其this指向obj,this.name就是b。
其次,getName()打印出a的原因:理由是此時的obj並不調用getName(),而是全局變量window,因此,結果是a
最後,obj2中,因為採用了立即執行函數,它返回一個函數,而當我們調用時,調用它的也是全局變量window,所以打印結果也是a。
需要注意的是,匿名函數內的this是指向window的,更準確的說是指向調用者。
1、必須瞭解new的過程
function Test() {
console.log(this.name);
}
Test(); // a
var test = new Test(); // undefined
function Test2() {
this.name = 'c';
}
var test2 = new Test2();
console.log(test2.name); // c
為什麼這個例子最終打印出來的是c呢?這裡new的過程不可忽略,new Test2() 其實執行了三步動作:
首先,創建一個空對象obj(var obj = {};),然後,將這個空對象的[[Prototype]](__proto__)成員指向了Test2函數對象prototype成員對象最後,將Test2函數對象的this指針替換成obj:
obj.__proto__ = Test2.prototype;
Test2.call(obj);
當沒有顯式返回值或者返回為基本類型、null時,默認將 this 返回(參考2)
因此,在這個例子中,當你使用new的時候,函數內部的this指向已經改變了,不再指向window。
主要應該搞清楚new的過程,然後就知道打印出c的原因了。
2、奇怪的return
看過上面的例子後,你是否覺得已經掌握了new的函數內的this指向?千萬別掉以輕心,在JavaScript中,多的是例外,如:
function Test3() {
this.name = 'd';
return {};
}
var test3 = new Test3();
console.log(test3.name); // undefined
function Test4() {
this.name = 'd';
return 1;
}
var test4 = new Test4();
console.log(test4.name); // d
可以再試試return 'd' | null | undefined中的一個或更多類型。
結論:如果return的是一個對象(null除外),那麼this指向的這個對象,否則this依舊指向實例對象。
閱讀更多 W3Cschool 的文章
關鍵字: 隨處可見 編程語言 JavaScript