最近混SF,恰巧又逢工做方面有了NodeJS的機會,迫切地有教別人怎麼寫JS的需求,
我發現JS這個東西其實真沒那麼容易理解。segmentfault
爲了加深和糾正本身對JS的理解,也爲了之後能直接甩別人一臉文章,因此開始挖這樣一個大坑:簡單易懂的ECMA規範導讀。
但願能以專題的形式有線索地基於ECMA標準介紹Javascript的方方面面。本文不是ECMA標準的中文翻譯,也不是Javascript的入門教程,
本文雖然以JS的常見問題切入,但並不適合想要快速瞭解這些問題的人(Google纔是快速瞭解問題的正解)。
本文的聚焦於標準如何決定了JS的各類行爲,JS引擎的水面下在發生些什麼。瀏覽器
本文描述的是ECMA262的5.1版本 也是如今最爲流行和主流的標準,
現代瀏覽器和NodeJS默認均遵循此標準。儘可能以英文原版爲基礎,爲了流暢,可能會使用某些名詞的中文翻譯,
但會將匹配的英文名詞以此種樣式
中出現一次以免誤解。app
咱們的第一個話題是:this指向哪裏?函數
The this keyword evaluates to the value of the ThisBinding of the current execution context.lua
計算this關鍵字時,取當前執行上下文的ThisBinding的值翻譯
執行上下文Execution Context
從邏輯上造成棧結構,棧頂(活躍)的執行上下文包含了追蹤當前正在執行的代碼的所有狀態。orm
執行上下文包含了LexicalEnvironment、VariableEnvironment和ThisBinding三部分,在這個話題中咱們主要關心ThisBinding,
也就是代碼中出現this所代指的值的綁定對象
從最簡單的開始
10.4.1 Entering Global Code
在進入全局代碼的流程中,規範明確指出:全局代碼對應的執行上下文中,
Set the ThisBinding to the global object.
因此全局代碼中,this指向全局對象
注意:this值this value
是不一樣於this關鍵詞的概念,是調用[[Call]]內部方法的參數之一,並不等同於用戶代碼中的this關鍵字
函數調用表達式CallExpression
的過程當中,按照標準的描述,
計算this值的僞代碼以下
if Type(ref) is <Reference> if IsPropertyReference(ref) thisValue := getBase(ref) else # assert Type(getBase(ref)) is <Environment Record> thisValue := getBase(ref).ImplicitThisValue() else thisValue := undefined
<Reference>
引用類型常見的有Environment Record
[]
運算,引用base是左值ImplicitThisValue
始終返回undefined綜上所述,排除with語句的狀況下,想讓thisValue不是undefined,就只有屬性訪問一種辦法而已。
計算獲得thisValue後,調用被調函數func的[[call]]
內部方法,提供thisValue做爲this的值
new表達式NewExpression
的執行過程
基本上委託給了[[Construct]]
內部方法,咱們看這個方法的定義,
關注其中第8步
Let result be the result of calling the [[Call]] internal property of F, providing
obj as the this value and providing the argument list passed into [[Construct]] as args.
其中F是構造函數,而obj是本次新建的對象,很是清楚。
前兩節咱們描述了兩種觸發函數體內代碼的辦法各自如何構造this值,但正如前述,this關鍵字的值是執行上下文中的ThisBinding決定的,
this值轉變爲ThisBinding的過程發生在調用[[Call]]
內部方法時,咱們看標準
Let funcCtx be the result of establishing a new execution context for function
code using the value of F's [[FormalParameters]] internal property, the passed
arguments List args, and the this value as described in 10.4.3.
阿哈,第一步就是創建新的執行上下文,其中thisBinding的構建在10.4.3 Entering Function Code
中描述,
if function-code is <strict code> ThisBinding = thisArg else if thisArg is null or thisArg is undefined ThisBinding = global object else if Type(thisArg) is not <Object> ThisBinding = ToObject(thisArg) else ThisBinding = thisArg
這就是魔術的祕密
That's this
in Javascript.
本節思考題: