本覺得對 JS 中的 this 已經很熟練了,再看完冴羽的博客後,才發現本身對 ES 規範知之甚少,原來我都是根據經驗在判斷 this,這篇文章會從最底層的 ES 規範上去介紹 this 的判斷。html
本文已同步到我的博客從 ES 規範 中理解 this,感謝鼓勵。git
第一次作這道題時,只對了第一題。。github
var value = 1; var foo = { value: 2, bar: function() { return this.value; } }; //示例1 console.log(foo.bar()); //示例2 console.log((foo.bar)()); //示例3 console.log((foo.bar = foo.bar)()); //示例4 console.log((false || foo.bar)()); //示例5 console.log((foo.bar, foo.bar)());
先想想這道題的答案,而後解釋一下緣由。算法
要完全弄明白上面的測試題,還得看規範文檔 😂ide
常見的幾種規範:函數
在 ECMAScript 規範中還有一種只存在於規範中的類型,它們的做用是用來描述語言底層行爲邏輯。測試
規範 8.7 The Reference Specification Typethis
Reference 類型實例大體長這樣:lua
var foo = { bar: function() { return this; } }; var fooReference = { base: EnvironmentRecord, name: 'foo', strict: false }; GetBase(fooReference); // EnvironmentRecord; var barReference = { base: 'foo', name: 'bar', strict: false }; GetBase(barReference); // foo;
GetBase(V)
. Returns the base value component of the reference V.HasPrimitiveBase(V)
. Returns true if the base value is a Boolean, String, or Number.IsPropertyReference(V)
. Returns true if either the base value is an object or HasPrimitiveBase(V) is true; otherwise returns false.規範 10.2.1.1.6 ImplicitThisValue()
undefined
.步驟1
將 ref 賦值爲 MemberExpression(簡單理解 MemberExpression 其實就是()左邊的部分)步驟2
判斷 ref 的類型
步驟3
若是 ref 是 Reference 類型
步驟4
若是 IsPropertyReference(ref) 是 true, 那麼 this 的值爲 GetBase(ref)步驟5
若是 base value 值是 Environment Record, 那麼 this 的值爲 ImplicitThisValue(ref)步驟6
若是 ref 不是 Reference 類型,那麼 this 的值爲 undefined提示
非嚴格模式下,this 的值爲 undefined 的時候,其值會被隱式轉換爲全局對象。
一、使用屬性讀取
規範:獲取 foo.bar
的返回類型。
二、交給函數調用規範,去解析 this。
Return a value of type Reference
whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.函數調用規範
步驟1
-> 步驟2
-> 步驟3
-> 步驟4
一、使用屬性讀取
規範:獲取 foo.bar
的返回類型。
二、使用括號運算符
規範:獲取 (foo.bar)
的返回類型。
三、交給函數調用規範,去解析 this。
查看規範 11.1.6 The Grouping Operator
This may be of type Reference
.函數調用規範
步驟1
-> 步驟2
-> 步驟3
-> 步驟4
一、使用賦值運算符
規範:獲取 foo.bar = foo.bar
的返回類型。
二、使用括號運算符
規範:獲取 (foo.bar = foo.bar)
的返回類型。
三、交給函數調用規範,去解析 this。
規範 11.13.1 Simple Assignment ( = )
GetValue(rref)
.函數調用規範
步驟1
-> 步驟2
-> 步驟6
一、使用邏輯與算法
規範:獲取 false || foo.bar
的返回類型。
二、使用括號運算符
規範:獲取 (false || foo.bar)
的返回類型。
三、交給函數調用規範,去解析 this。
規範 11.11 Binary Logical Operators
GetValue(rref)
.函數調用規範
步驟1
-> 步驟2
-> 步驟6
一、使用逗號操做符
規範:獲取 foo.bar, foo.bar
的返回類型。
二、使用括號運算符
規範:獲取 (foo.bar, foo.bar)
的返回類型。
三、交給函數調用規範,去解析 this。
GetValue(rref)
. 返回的是 GetValue 後的值,不是一個 Refernce。函數調用規範
步驟1
-> 步驟2
-> 步驟6
function foo() { console.log(this); } foo(); GetBase(fooReference); // EnvironmentRecord;
一、使用標識符解析
規範:獲取 foo
的返回類型。
二、交給函數調用規範,去解析 this。
規範 10.3.1 Identifier Resolution
is always a value of type Reference
with its referenced name component equal to the Identifier String.函數調用規範
步驟1
-> 步驟2
-> 步驟3
-> 步驟5
遇到問題時,儘可能從原理的角度看待問題,不要憑經驗辦事情,不妨多研究研究底層規範。
tip 參考資料
JavaScript 深刻之從 ECMAScript 規範解讀 this
ES5 規範文檔