JS中this關鍵字、call、apply方法
首先,必須搞清楚在JS裏面,函數的幾種調用方式:
-
普通函數調用
-
作為方法來調用
-
作為構造函數來調用
-
使用apply/call方法來調用
-
Function.prototype.bind方法
-
es6箭頭函數
誰調用這個函數或方法,this關鍵字就指向誰。
普通函數調用
function person(){ this.name="xl"; console.log(this); console.log(this.name); } person(); //輸出 window xl
在這段代碼中person
person
是作為全局對象window
的一個方法來進行調用的,即window.person()
;
所以這個地方是window
對象調用了person
方法,那麽person
函數當中的this
即指window
,同時window
還擁有了另外一個屬性name
,值為xl
.
var name="xl"; function person(){ console.log(this.name); } person(); //輸出 xl
同樣這個地方person
作為window
的方法來調用,在代碼的一開始定義了一個全局變量name
,值為xl
,它相當於window
的一個屬性,即window.name="xl"
person
的時候this
是指向window
的,因此這裏會輸出xl
.
作為方法來調用
在上面的代碼中,普通函數的調用即是作為window
對象的方法進行調用。顯然this
關鍵字指向了window
對象.
再來看下其他的形式
var name="XL"; var person={ name:"xl", showName:function(){ console.log(this.name); } } person.showName(); //輸出 xl //這裏是person對象調用showName方法,很顯然this關鍵字是指向person對象的,所以會輸出namevar showNameA=person.showName; showNameA(); //輸出 XL //這裏將person.showName方法賦給showNameA變量,此時showNameA變量相當於window對象的一個屬性,因此showNameA()執行的時候相當於window.showNameA(),即window對象調用showNameA這個方法,所以this關鍵字指向window
再換種形式:
var personA={ name:"xl", showName:function(){ console.log(this.name); } } var personB={ name:"XL", sayName:personA.showName } personB.sayName(); //輸出 XL //雖然showName方法是在personA這個對象中定義,但是調用的時候卻是在personB這個對象中調用,因此this對象指向
作為構造函數來調用
function Person(name){ this.name=name; } var personA=Person("xl"); console.log(personA.name); // 輸出 undefined console.log(window.name);//輸出 xl //上面代碼沒有進行new操作,相當於window對象調用Person("xl")方法,那麽this指向window對象,並進行賦值操作window.name="xl". var personB=new Person("xl"); console.log(personB.name);// 輸出 xl //這部分代碼的解釋見下
call/apply方法的調用
在JS裏函數也是對象,因此函數也有方法。從Function.prototype上繼承到Function.prototype.call/Function.prototype.apply
方法call/apply
方法最大的作用就是能改變this
關鍵字的指向.
Obj.method.apply(AnotherObj,arguments);
var name="XL"; var Person={ name:"xl", showName:function(){ console.log(this.name); } } Person.showName.call(); //輸出 "XL" //這裏call方法裏面的第一個參數為空,默認指向window。 //雖然showName方法定義在Person對象裏面,但是使用call方法後,將showName方法裏面的this指向了window。因此最後會輸出"XL"; funtion FruitA(n1,n2){ this.n1=n1; this.n2=n2; this.change=function(x,y){ this.n1=x; this.n2=y; } } var fruitA=new FruitA("cheery","banana"); var FruitB={ n1:"apple", n2:"orange" }; fruitA.change.call(FruitB,"pear","peach"); console.log(FruitB.n1); //輸出 pear console.log(FruitB.n2);// 輸出 peach
FruitB
調用fruitA
的change
方法,將fruitA
中的this
綁定到對象FruitB
上。
Function.prototype.bind()方法
var name="XL"; function Person(name){ this.name=name; this.sayName=function(){ setTimeout(function(){ console.log("my name is "+this.name); },50) } } var person=new Person("xl"); person.sayName() //輸出 “my name is XL”; //這裏的setTimeout()定時函數,相當於window.setTimeout(),由window這個全局對象對調用,因此this的指向為window, 則this.name則為XL
那麽如何才能輸出"my name is xl"
呢?
var name="XL"; function Person(name){ this.name=name; this.sayName=function(){ setTimeout(function(){ console.log("my name is "+this.name); }.bind(this),50) //註意這個地方使用的bind()方法,綁定setTimeout裏面的匿名函數的this一直指向Person對象 } } var person=new Person("xl"); person.sayName(); //輸出 “my name is xl”;
這裏setTimeout(function(){console.log(this.name)}.bind(this),50);
,匿名函數使用bind(this)
方法後創建了新的函數,這個新的函數不管在什麽地方執行,this
都指向的Person
,而非window
,因此最後的輸出為"my name is xl"而不是"my name is XL"
另外幾個需要註意的地方:setTimeout/setInterval/匿名函數執行
的時候,this
默認指向window對象
,除非手動改變this的指向。在《javascript高級程序設計》當中,寫到:“超時調用的代碼(setTimeout
)都是在全局作用域中執行的,因此函數中的this的值,在非嚴格模式下是指向window對象,在嚴格模式下是指向undefined”。本文都是在非嚴格模式下的情況。
var name="XL"; function Person(){ this.name="xl"; this.showName=function(){ console.log(this.name); } setTimeout(this.showName,50); } var person=new Person(); //輸出 "XL" //在setTimeout(this.showName,50)語句中,會延時執行this.showName方法 //this.showName方法即構造函數Person()裏面定義的方法。50ms後,執行this.showName方法,this.showName裏面的this此時便指向了window對象。則會輸出"XL";
修改上面的代碼:
var name="XL"; function Person(){ this.name="xl"; var that=this; this.showName=function(){ console.log(that.name); } setTimeout(this.showName,50) } var person=new Person(); //輸出 "xl" //這裏在Person函數當中將this賦值給that,即讓that保存Person對象,因此在setTimeout(this.showName,50)執行過程當中,console.log(that.name)即會輸出Person對象的屬性"xl"
本文引用自http://www.cnblogs.com/lisha-better/p/5684844.html
JS中this關鍵字、call、apply方法