1、this
JavaScript中的this,總是指向一個對象 ,而具體指向哪個對象是在運作時基于函數的執行環境動态綁定的,而非函數被聲明時的環境。
this的指向大緻可以分以下4種:
- 作為對象的方法調用
- 作為普通函數調用
- 構造器調用
- Function.prototype.call或Function.prototype.apply調用
1、作為對象的方法調用
var obj = {
name:"Tome",
getName:function(){
alert(this == obj); // true
alert(this.name); // Tome
}
};
obj.getName();
因為obj字面量對象調用了getiName()方法,是以this就代表了obj字面量對象。字面量對象一建立就在記憶體中有自己的空間。
2、作為普通函數調用
當函數不作為對象的屬性被調用時,此時this總是指向全局對象。在浏覽器的JavaScript中,這個全局對象就是window對象。
var name = "globalName";
var getName = function(){
return this.name;
};
alert(getName());
或
window.name = "globalNameA";
var getName = function(){
return this.name;
};
alert(getName());
或
window.name = "globalNameB";
var myObject = {
name:"Jhony",
getName:function(){
return this.name;
}
}
var getName = myObject.getName;
alert(getName()); // globalNameB
alert(myObject.getName()); // Jhony
var getName = myObject.getName這一句隻是把myObject字面的對象方法借來用。而裡面用到的this是根據具體的運作環境來綁定的,是以當在myObject字面量對象外且不作為myObject的屬性來調用getName方法時,this指向全局對象。當作為myObject對象的屬性來調用時,即myObject.getName()調用時,this又指向字面量對象myObject。
注意:有個很趣的現象
window.id = "window";
document.getElementById("root").onclick = function(){
alert(this.id); // root
var callback = function(){
alert(this.id);
};
callback(); // window
}
此時callback裡的this是指向了全局對象window而不是id為root的元素對象,為什麼會這樣呢,因為callback方法前面沒有指明調用對象,callback方法不是作為id為root元素對象的屬性來調用的,是以this預設指向全局對象。如果你要callback方法裡的this指向id為root元素,怎麼辦?可以通過call或apply方法,重新指定this的指向,如:
.id = "window";
document.getElementById("root").onclick = function(){
alert(this.id); // root
var callback = function(){
alert(this.id);
};
callback.call(document.getElementById("root")); // root
callback.apply(document.getElementById("root")); // root
}
3、構造器調用
JavaScript中沒有類,但是可以從構造器中建立對象,同時也提供了new運算符,但他們隻是用來申請一個記憶體空間,然後通過這個構造器方法來對這個空間進行指派。
var MyClass = function(name){
this.name = name;
}
function MyClass1(name){
this.name = name;
}
var myClass = new MyClass("Tome");
alert(myClass.name)
var myClass1 = new MyClass1("Haha");
alert(myClass1.name)
構造器會幫我們申請記憶體空間後,然後把這個對象隐式地傳回來,再用構造器方法對其進行指派。不要在構造器中顯示return傳回其他東西,否則将會取代之前申請好的對象。前面的功夫就白做了,如:
var MyClass = function(name){
this.name = name;
return {
name:"Jeety"
}
}
var myClass = new MyClass("Tome");
alert(myClass.name) // Jeety
上面這個反例裡做事就是一開始去申請了記憶體空間,然後用構造器函數對記憶體空間進行了指派,讓記憶體有了一個name值為Tome,結果在最後又去建立了一個字面量對象,在記憶體另開一個空間,把name指派了Jeety,最後把前面那個抛棄了,傳回這個字面量對象。不要這樣做, 我真想說,這是吃飽了撐的嗎?
4、Function.prototype.call或Function.prototype.apply調用
.id = "window";
document.getElementById("root").onclick = function(){
alert(this.id); // root
var callback = function(){
alert(this.id);
};
callback();
callback.call(document.getElementById("root")); // root
callback.apply(document.getElementById("root")); // root
}