1、基本概念
MDN的官方解釋:與其他語言相比,函數的this 關鍵字在JavaScript 中的表現略有不同,此外,在嚴格模式和非嚴格模式之間也會有一些差異。在絕大多數情況下,函數的呼叫方式決定了this的值。 this不能在執行期間被賦值,在每次函數被呼叫時this的值也可能會不同。
簡而言之:
1.this指向的物件稱為函數的上下文物件context;
2.this的指向取決於函數被呼叫方式
不管函數怎麼呼叫的天花亂墜,我們只要記住這幾點即可清晰的找出this的指向。
2、小實驗
function foo(){ console.log(this); }
面試官問你this指向哪裡,當然大聲回答不知道,原因:誰調用指向誰,函數都沒被調用,確實不知道指向。
小結:直接透過函數名稱來呼叫函數,this指向全域變數window;透過物件.函數名稱呼叫函數,this指向該物件。
3、DOM物件呼叫函數時this的指向問題
1.透過選擇器選擇元素加事件屬性來綁定事件,this指向該DOM對象,範例如下:
document.getElementById('btn').onclick=function(){ console.log('click'); //click console.log(this); //<button id="btn">button</button> }
2.直接在DOM標籤中寫事件,this指向window,我們可以透過吧this作為參數傳入方法中再使用,例子如下:
html: <button onclick="modify()">add</button> <span id="count">0</span> <button onclick="modify()">reduce</button> script: // 操作方法 function modify(){ console.log(this); //window }
因為這個時候是直接呼叫方法的,所以this指向全域window對象,那麼問題來了,我們想判斷我們點擊的是哪一個按鈕,該怎麼做呢,我們可以把this的值作為參數傳入方法中再使用,例子如下。
html: <button onclick="modify(this)">add</button> <span id="count">0</span> <button onclick="modify(this)">reduce</button> script: // 操作方法 function modify(_this){ console.log(_this); // <button onclick="modify(this)">add</button> // <button onclick="modify(this)">reduce</button> }
4.物件中this的指向問題
先看一個簡單的例子:
var a=1; function printA(){ console.log(this.a); } var obj={ a:2, foo:printA, bar:function(){ printA(); } } obj.foo(); //2 obj.bar(); //1var foo=obj.foo;foo(); //1
我們定義了一個全域變數a和一個列印a的全域變數方法,之後又定義了一個obj對象,其中包含a屬性和foo,bar兩個方法。當我們呼叫obj.foo()印了2,呼叫obj.bar()印了1.
分析:
不管printA在哪裡定義的,我們this的指向只取決於被誰調用的。在obj.foo(),foo的屬性值為printA,被obj直接調用,所以this指向obj,this.a就是obj.a=2了;
當我們調用obj.bar()時,bar的屬性值為function(){printA()},沒有明確哪個物件來呼叫printA方法,this預設指向全域物件window,所以this.a=window.a=1;
第三種情況我們把obj.foo值賦予了foo變量,在調用的時候就相當於window.foo()了,打印1。
小結:this的指向不是函數宣告是綁定的,而是在函數運行過程中動態綁定的。
5.改變this的指向方法:applay call bind
話不多話:寫了一個例子,大家先看,萬一比喻不恰當,大家能理解其中意思即可
var liLei={ name:'liLei', money:10, buyPen:function(){ this.money=this.money-1; console.log(this.name+" have money:"+this.money) } } var hanMeiMei={ name:'hanMeiMei', money:20, buyPan:function(){ this.money=this.money-2; console.log(this.name+" have money:"+this.money) } } liLei.buyPen(); // liLei have money:9 hanMeiMei.buyPan(); //hanMeiMei have money:18
例子很好理解,輸出的結果相信大家也能看得明白,哪天,韓梅梅想買一個盆,她買不了,因為她還沒有這個方法,她一想:我沒有這個方法,但是李雷有啊,我打電話給李雷把錢他讓他幫我買啊;後來李雷想買一個盤,實現方法也是如此。那麼,在程式碼中如何實現呢?
JavaScript有好幾個方法可以實現:call,apply,bind。
call方法:
語法:call(thisObj,Object)
定義:呼叫一個物件的一個方法,以另一個物件取代當前對象。
說明:
call 方法可以用來取代另一個物件呼叫一個方法。 call 方法可將一個函數的物件上下文從初始的上下文變更為由 thisObj 指定的新物件。如果沒有提供 thisObj 參數,那麼 Global 物件被用作 thisObj。
liLei.buyPen.call(hanMeiMei); //hanMeiMei have money:19 hanMeiMei.buyPan.call(liLei); //liLei have money:8
apply方法:
語法:apply(thisObj,[argArray])
定義:應用某一物件的一個方法,用另一個物件替換當前物件。
說明:
如果 argArray 不是一個有效的陣列或不是 arguments 對象,那麼將導致一個 TypeError。如果沒有提供 argArray 和 thisObj 任何一個參數,那麼 Global 物件將被用作 thisObj, 並且無法被傳遞任何參數。
liLei.buyPen.apply(hanMeiMei); //hanMeiMei have money:19 hanMeiMei.buyPan.apply(liLei); //liLei have money:8
bind方法:
liLei.buyPen.bind(hanMeiMei)(); //hanMeiMei have money:19 hanMeiMei.buyPan.apply(liLei)(); //liLei have money:8
小結:三種方法的相同指出是:可以改變this的指向,不同之處是:apply接受的參數為一個數組,call接收的參數為一個個獨立的值;apply,call會直接呼叫方法,bind改變this的指向回傳一個方法不呼叫。
推薦教學:js教學
以上是關於js中的This指向問題的介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!