首先,看一段代碼:函數
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 值,而再也不是左值,就不能賦值,上面的代碼就會出錯。而以上代碼運行徹底正確,所以能夠證實:表達式的括號必定不會求值。
其實,表達式中的括號 () 除了在函數後面用做調用運算符以外,其餘狀況根本就不是一個運算符,僅僅用於提高運算關係的優先級!