1. 程式人生 > >this、call和apply

this、call和apply

JavaScript總是指向一個物件,指向哪個物件是在執行時基於函式的執行環境動態繫結的,而非函式宣告時的環境。

this的指向

除去不常用的with和eval的情況,具體到實際應用中,this的志向大致可以分為以下4種。

  1. 作為物件的方法呼叫。
  2. 作為普通函式呼叫。
  3. 構造器呼叫。
  4. Function.prototype.call或Function.prototype.apply呼叫。

作為物件的方法呼叫

當函式作為物件的方法被呼叫時,this指向該物件:

var obj = {
	a:1,
	getA:function(){
		alert(this === obj);//輸出:true
		alert(this.a);// 輸出:1
	}
};
obj.getA();

作為普通函式呼叫

當函式不作為物件的屬性被呼叫時,也就是我們常說的普通函式,此時的this總是指向全域性物件。在瀏覽器的JavaScript裡,這個全域性物件是window物件。

window.name = 'globalName';
var getName = function(){
	return this.name;
};
console.log(getName());// 輸出:globalName
//或者
window.name = 'globalName';
var myObject = {
	name: 'zee',
	getName: function(){
		return this.name;
	}
};
var getName = myObject.getName;
consolelog(getName());// globalName

構造器呼叫

JavaScript中沒有類,但是可以從構造器中建立物件,當用new操作符呼叫函式時,該函式總會返回一個物件,構造器裡的this就指向返回的這個物件

var MyClass = function(){
	this.name = 'zee';
};
var obj = new MyClass();
alert(obj.name);// 輸出:zee

但用new構造器時,還要注意一個問題,如果構造器顯示地返回了一個object型別的物件,那麼此次運算結果最終會返回這個物件

var MyClass = function(){
	this.name = 'zee';
	return {
		name: anne'
	}
};
var obj = new MyClass();
alert(obj.name); // 輸出:anne

如果構造器不顯式地返回任何資料,或者是返回一個非物件型別的資料,就不會造成上述問題:

var MyClass = function(){
	this.name = 'zee';
	return 'anne';// 返回string型別
};
var obj = new MyClass();
alert(obj.name); // 輸出:zee

Function.prototype.call或Function.prototype.apply呼叫

跟普通的函式呼叫相比,用Function.protoype.call或Function.prototype.apply可以動態地改變傳入函式的this

var obj1 = {
	name: 'zee',
	getName: function(){
		return this.name;
	}
};
var obj2 = {
	name: 'anne'
};
console.log(obj1.getName());// 輸出:zee
console.log(obj1.getName.call(obj2));// 輸出:anne

call和apply

call和apply用途

  1. 改變this的指向
var obj1 = {
	name: 'zee'
};
var obj2 = {
	name: 'anne'
};
window.name = 'window';
var getName = function(){
	alert(this.name);
};
getName();//window
getName.call(obj1);//zee
getName.call(obj2);//anne
document.getElementById('div1').onclick = function(){
	var func = function(){
		alert(this.id);
	}
	func.call(this);
}
  1. Function.prototype.bind 大部分高階瀏覽器都實現了內建的Function.prototype.bind,用來指定函式內部的this指向,即使沒有原生的Function.prototype.bind實現,我們可以模擬實現
Function.prototype.bind = function(context){
	var self = this; //儲存原函式
	return function(){// 返回一個新的函式
		return self.apply(context, arguments);//執行新的函式的時候,會把之前傳入的context當作新函式體內的this
	}
};
var obj = {
	name: 'zee'
};
var func = function(){
	alert(this.name);//輸出zee
}.bind(obj);
func();
  1. 借用其他物件的方法
var A = function(name){
	this.name = name;
};
var B = function(){
	A.apply(this, arguments);
};
B.prototype.getName = function(){
	return this.name;
};
var b = new B('zee');
console.log(b.getName());//輸出:'zee'