ECMAScript語言類型
ECMAScript的類型分為語言類型和規(guī)范類型
- 語言類型就是我們常說的的Undefined, Null, Boolean, String, Number, 和 Object
- 規(guī)范類型就是用來描述語言底層行為邏輯的,并不存在于實際的js代碼中,規(guī)范類型包括:Reference, List, Completion, Property Descriptor, Property Identifier, Lexical Environment, 和 Environment Record。
Reference
ECMAScript將Reference定義為"被解析的命名綁定",Reference是用來解釋一些諸如delete、typeof以及賦值等操作行為的
A Reference is a resolved name binding.
A Reference consists of three components, the base value, the referenced name and the Boolean valued strict reference flag.
The base value is either undefined, an Object, a Boolean, a String, a Number, or an environment record (10.2.1).
A base value of undefined indicates that the reference could not be resolved to a binding. The referenced name is a String.
Reference的內(nèi)容有:
- base value:屬性所在的對象或者 EnvironmentRecord(執(zhí)行上下文或執(zhí)行環(huán)境)。他的值可能是它的值只可能是 undefined, an Object, a Boolean, a String, a Number, or an environment record 其中的?種
- referenced name:屬性的名稱
- strict reference:是否開啟了嚴格模式
可以認為Reference是一個不帶原型的,有且只有3個屬性的對象
舉個??:
var foo = 1;
// 對應的Reference是:
var fooReference = {
base: EnvironmentRecord,
name: 'foo',
strcit: false
}
var foo = {
bar: function () {
return this;
}
};
foo.bar();
// bar對應的Reference是:
var BarReference = {
base: foo, // 屬性所在的對象是foo
propertyName: 'bar',
strict: false
};
規(guī)范中提供了獲取Reference組成部分的方法,比如GetBase和IsPropertyReference
- GetBase,返回 reference 的 base value。
GetBase(V). Returns the base value component of the reference V.
- IsPropertyReference,如果 base value 是一個對象,就返回true
IsPropertyReference(V). Returns true if either the base value is an object or HasPrimitiveBase(V) is true; otherwise returns false.
-
GetValue,從Reference類型中獲取對應值
使用方法如下
var foo = 1; var fooReference = { base: EnvironmentRecord, name: 'foo', strict: false }; // 獲取對象屬性真正的值,foo = 1; GetValue(fooReference) // 1;注意: 調(diào)用GetValue返回的是具體的值,而不是一個Reference
如何確定this的值
規(guī)范中有描述當函數(shù)調(diào)用的時候,如果確定this的取值
-
計算MemberExpression的結(jié)果并賦值給ref
什么是MemberExpression呢?簡單理解就是在函數(shù)調(diào)用中,()左邊的是MemberExpression
- MemberExpression是()左邊部分這句話并不準確,它可以是一個普通的對象,甚至是一個普通普通變量;但如上述所說,是大致準確的
舉個??:
function foo() { console.log(this) } foo(); // MemberExpression 是 foo function foo() { return function() { console.log(this) } } foo()(); // MemberExpression 是 foo() var foo = { bar: function () { return this; } } foo.bar(); // MemberExpression 是 foo.bar -
判斷ref是不是一個Reference類型
關(guān)鍵在于看規(guī)范如何處理各種MemberExpression,返回的是不是一個Reference類型
- 如果ref是Reference,并且IsPropertyReference(ref)是true,那么this的值為GetBase(ref)
- 如果ref是Reference,并且base value的值是EnvironmentRecord,那么this的值是ImplicitThisValue(ref)
- 如果ref不是Reference,那么this的值是undefined
舉個??:
var value = 1; function test() { console.log('test'); }; var foo = { value: 2, bar: function () { return this.value; } } //示例1 console.log(test()); //示例2 console.log(foo.bar()); //示例3 console.log((foo.bar)()); //示例4 console.log((foo.bar = foo.bar)()); //示例5 console.log((false || foo.bar)()); //示例6 console.log((foo.bar, foo.bar)());- test()
這個例子中,這個例子中,MemberExpression就是test,test是一個標識符,執(zhí)行的時候會發(fā)生什么呢
An Identifier is evaluated by performing Identifier Resolution as specified in 10.3.1. The result of evaluating anIdentifier is always a value of type Reference.
標識符被解析的時候會進行標識符解析(Identifier Resolution),結(jié)果始終是Reference的值,接著看看dentifier Resolution規(guī)范
1.Let env be the running execution context’s LexicalEnvironment.
...
3.Return the result of calling GetIdentifierReference function passing env, Identifier, and strict as arguments.返回GetIdentifierReference方法的結(jié)果,再來看看
GetIdentifierReference方法Return a value of type Reference whose base value is envRec, whose referenced name is name, and whose strict mode flag is strict.
此處返回了一個 base value 是 envRec 也就是 10.3.1中傳入的 execution context’s LexicalEnvironment
(詞法環(huán)境包含環(huán)境記錄項Environment Record,它是規(guī)范用來管理當前作用域下面變量的類型,此處不用理解,知道它返回了這個東東就行了)根據(jù)這個過程,我們確定MemberExpression test的計算結(jié)果是一個Reference類型
fooReference = { "base": LexicalEnvironment, "name": "test", "strict": false }根據(jù)如果ref是Reference,并且base value的值是EnvironmentRecord,那么this的值是ImplicitThisValue(ref)
根據(jù)規(guī)范
(10.2.1.1.6 ImplicitThisValue())[http://es5.github.io/#x10.2.1.1.6]Declarative Environment Records always return undefined as their ImplicitThisValue.
可以看到,base value值為EnvironmentRecord時,ImplicitThisValue的結(jié)構(gòu)是undefined,對應到 JavaScript 代碼中的 this,還差最后一步:
Else if thisArg is null or undefined, set the ThisBinding to the global object.
this 為 undefined,非嚴格模式下,this 的值為 undefined 的時候,其值會被隱式轉(zhuǎn)換為全局對象。
由此得知:test()執(zhí)行時,this = global = window
---
2. foo.bar()
這個例子中,foo.bar是一個屬性訪問,那么規(guī)范中也給出執(zhí)行屬性訪問的時候會發(fā)生什么
> The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows:
1.Let baseReference be the result of evaluating MemberExpression.<br>
2.Let baseValue be GetValue(baseReference)<br>
8.Return a value of type Reference whose base value is baseValue and whose referenced name ispropertyNameString, and whose strict mode flag is strict
baseReference 等于執(zhí)行 MemberExpression, 在此處為foo.bar的結(jié)果,按照前文,是返回一個Reference類型的值
```JavaScript
var reference_foo_bar = {
"base": foo, // baseValue 等于 GetValue(baseReference)
"name": "bar",
"strict": false
}
```
根據(jù)`如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么 this 的值為 GetBase(ref)`, IsPropertyReference(ref) 根據(jù)base value 是否是一個對象來返回true,
此處IsPropertyReference(ref) 結(jié)果為 true,因此
this的值為
this = GetBase(ref),
GetBase 也已經(jīng)鋪墊了,獲得 base value 值,這個例子中就是foo,所以 this 的值就是 foo ,示例1的結(jié)果就是 2!
詞法環(huán)境LexicalEnvironment
官方對詞法環(huán)境的解釋如下:
詞法環(huán)境是一種規(guī)范類型,基于 ECMAScript 代碼的詞法嵌套結(jié)構(gòu)來定義標識符與特定變量和函數(shù)的關(guān)聯(lián)關(guān)系。詞法環(huán)境由環(huán)境記錄(environment record)和可能為空引用(null)的外部詞法環(huán)境組成。
詞法環(huán)境由兩個部分組成
環(huán)境記錄(enviroment record),存儲變量和函數(shù)聲明
對外部環(huán)境的引用(outer),可以通過它訪問外部詞法環(huán)境