首頁  >  文章  >  web前端  >  JavaScript 之 this 詳解

JavaScript 之 this 詳解

高洛峰
高洛峰原創
2016-11-28 13:59:24979瀏覽

JavaScript中的this總是讓人迷惑,應該是js眾所周知的坑之一。 個人也覺得js中的this不是一個好的設計,由於this晚綁定的特性,它可以是全局對象,當前對象,或者…有人甚至因為坑大而不用this。


其實如果完全掌握了this的工作原理,自然就不會走進這些坑。來看以下這些情況中的this分別會指向什麼:

1.全域程式碼中的this
1 alert(x);
// 全域變數x值為2

 


全域範圍內的this將會指向全域對象,在瀏覽器中即使window。

2.作為單純的函數呼叫
  function fooCoder(x) {
this.x = x;
}
fooCoder(2);
alert(x);
// 全域變數值為2

這裡this指向了全域對象,即window。在嚴格模式中,則是undefined。


3.作為對象的方法調用

 var name = "clever coder";

var person = {
name : "foocoder",
hello : function(sth){
console.log(this.name + " says " + sth);
}
}
person.hello("hello world");

 

輸出foocoder says hello world。 this指向person對象,即當前對象。

4.作為建構子

1 new FooCoder();

函數內部的this指向新建立的物件。

5.內部函數

  var name = "clever coder";

var person = {

name : "foocoder",

hello : function(sth){
var saysgello = function(sth){
var saysgol. (this.name + " says " + sth);
};
sayhello(
}

person.hello("hello world");

//clever coder says hello world


this沒有按預想的綁定到外層函數物件上,而是綁定到了全域物件。方式是將this作為變數保存下來,一般約定為that或self:

 var name = "clever coder";

var person = {

name : "foocoder",
hello : function(sth){
var that = this ;
var sayhello = function(sth) {
console.log(that.name + " says " + sth);
};
sayhello(sth);
}
}
personhello("hhello world");
//foocoder says hello world

 

6.使用call和apply設定this

1 person.hello.call(person, "world");


1 person.hello.call(person, "world");

1 person.hello.call(person, "world");

1 person.hello.call(person, "world");

1 person.hello.call(person, "world");

1 person.hello.call(person, "world");


apply和call陣列傳入,而不是分開傳入。 [,argArray] );
// 參數數組,argArray

 


兩者都是將某個函數綁定到某個具體物件上使用,自然此時的this會被明確的設定為第一個參數。呼叫時,this指向該物件。上層函數的this,如果需要,可以用一個變數保存上層函數的this。

再總結的簡單點,如果在函數中使用了this,只有在該函數直接被某物件呼叫時,該this才指向該物件。

 obj.foocoder();

foocoder.call(obj, ...);

foocoder.apply(obj, …);

 

更進一步

我們可能經常寫這樣的程式碼: ("#some-ele").click = obj.handler;


如果在handler中用了this,this會綁定在obj上麼?顯然不是,賦值以後,函數是在回呼中執行的,this會綁定到$(“#some-div”)元素上。這就需要理解函數的執行環境。本文不打算長篇贅述函數的執行環境,可以參考《javascript高階程式設計》中執行環境與作用域鏈的相關介紹。這裡要指出的時,理解js函數的執行環境,會更能理解this。


那我們如何解決回呼函數綁定的問題? ES5中引入了一個新的方法,bind():

  fun.bind(thisArg[, arg1[, arg2[, ...]]])

thisArg

 

當綁定函數被呼叫時,Arg

 

當綁定函數被調用,Arg


 

當綁定函數被調用,Arg

 

當綁定函數被調用,Arg

 

當綁定函數被調用,Arg

 🎜🎜當綁定函數被調用,Arg🎜🎜 🎜🎜當綁定函數被調用,Arg🎜參數會作為原始函數運行時的this指向.當使用new 操作符調用綁定函數時,該參數無效.🎜🎜1 arg1, arg2, ...🎜🎜當綁定函數被調用時,這些參數加上綁定函數本身的參數會依照順序作為原函數運行時的參數.🎜


該方法建立一個新函數,稱為綁定函數,綁定函數會以創建它時傳入bind方法的第一個參數作為this,傳入bind方法的第二個以及以後的參數加上綁定定函數運行時本身的參數按照順序作為原函數的參數來調用原函數.

顯然bind方法可以很好地解決上述問題。
1
2 $("#some-ele").click(person.hello.bind(person));
//對應元素點擊時,輸出foocoder says hello world

 


其實容易模擬,我們看下Prototype.js中bind方法的源碼:
  Function.prototype.bind = function(){
var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift ();
return function(){
return fn.apply(object,
args.concat(Array.prototype.slice.call(arguments)));
};
};


🎜
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn