面試題-淺談JavaScript中的This指向問題

  各位小夥伴在面試中被面試官問道this指向問題必定很多吧,同時還被問道apply,call和bind的用法區別,如今,就來簡單的聊一聊this到底指向何方。html

1.基本概念面試

MDN的官方解釋:與其餘語言相比,函數的 this 關鍵字在 JavaScript 中的表現略有不一樣,此外,在嚴格模式和非嚴格模式之間也會有一些差異。在絕大多數狀況下,函數的調用方式決定了this的值。this不能在執行期間被賦值,而且在每次函數被調用時this的值也可能會不一樣。數組

簡而言之:瀏覽器

  1.this指向的對象稱爲函數的上下文對象context;  app

  2.this的指向取決於函數被調用方式 函數

無論函數怎麼調用的天花亂墜,咱們只要記住這幾點便可清晰的找出this的指向。this

2.小試牛刀spa

function foo(){
  console.log(this);
}

面試官問你this指向哪裏,固然大聲回答不知道,緣由:誰調用指向誰,函數都沒被調用,確實不知道指向。code

 小結:直接經過函數名來調用函數,this指向全局變量window;經過對象.函數名調用函數,this指向該對象。htm

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(); //1
var 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的指向返回一個方法不調用。

注:有些低版本的瀏覽器不支持函數使用bind方法,咱們在作瀏覽器兼容時能夠加以判斷,具體實現方法暫不贅述。

 

  以上就是我的對於this的指向問題的理解,咱們只需記住一點:this指向-誰調用,指向誰。不得不說JavaScript真是個奇妙的世界,文中有紕漏不足的地方,歡迎指正。


 

參考資料:

MDN-this

傑瑞教育

外婆的彭湖灣

轉載請註明出處,謝謝!

相關文章
相關標籤/搜索