爲何 (obj.foo)() 調用的執行環境中的 this 就是 obj ?

首先,看一段代碼:函數

var obj = {
  foo: function() {
    if( this === obj ) {
      console.log('this is the obj !');
    }
    else {
       console.log('this is not the obj !');
    }
  }
}

用不一樣的方式調用obj的foo方法有不一樣的結果:this

obj.foo();          // this is obj !
(obj.foo)();        // this is obj !
(0 || obj.foo)();   // this is not obj !

第一種狀況,obj.foo(); 無需解釋。對象

最後一種狀況也很好解釋,(0 || obj.foo)(); 的第一個括號內是一個邏輯運算表達式,按照 || 運算符的處理邏輯,該表達式返回的是 obj.foo 的求值結果。而 obj.foo 的求值結果是一個純粹的函數值,於是在函數值被調用的執行環境中,this 確定不是原來的 obj 。ip

但第二種狀況比較費解!

按直覺,(obj.foo) 應該會返回一個純粹的函數值,所以在該函數值被調用的執行環境中,this 應該不是原來的 obj 。但實際狀況並不是如此!io

爲何會這樣?console

這得從 JavaScript 的成員表達式以及括號()在表達式中的做用提及。function

首先,必定要明白 obj.foo 是一個成員表達式,其值包含對象 obj 和屬性 foo 兩部分。成員表達式的值同時也是一個左值,即,其能夠用在賦值表達式的左側,是能夠被賦值的。變量

當左值參與表達式運算時,會觸發左值求值操做,從而將其轉換成通常值(俗稱,右值)以後才參與運算。這就是爲何 (0 || obj.foo) 中的 || 運算符會觸發將 obj.foo 求值爲函數值的緣故。方法

但在 (obj.foo) 表達式中,括號內並無任何運算符,因此 obj.foo 依舊是成員表達式的值。co

那麼,包裹表達式的括號 ( ) 會觸發對其包裹的表達式進行求值操做嗎?

答案是:包裹表達式的括號 ( ) 不會觸發求值操做!

所以,( obj.foo ) 依舊返回了成員表達式的值,對其發起調用操做,就是基於對象 obj 和 屬性 foo 發起調用,因此其調用執行環境中的 obj 就是 this !

關於 表達式中的括號 () 不觸發求值,還能夠用如下代碼證實:

var x;
(x) = 123;    // 這是正確的寫法,並能正確運行!

上面代碼中,x 是一個變量,也是一個左值。若是 (x) 的括號觸發了對 x 的求值,其結果必定是 undefined 值,而再也不是左值,就不能賦值,上面的代碼就會出錯。而以上代碼運行徹底正確,所以能夠證實:表達式的括號必定不會求值。

其實,表達式中的括號 () 除了在函數後面用做調用運算符以外,其餘狀況根本就不是一個運算符,僅僅用於提高運算關係的優先級!

相關文章
相關標籤/搜索