《从ECMAScript规范解读this》笔记

ECMAScript语言类型

ECMAScript的类型分为语言类型和规范类型

  1. 语言类型就是我们常说的的Undefined, Null, Boolean, String, Number, 和 Object
  2. 规范类型就是用来描述语言底层行为逻辑的,并不存在于实际的js代码中,规范类型包括: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的内容有:

  • base value:属性所在的对象或者 EnvironmentRecord(执行上下文或执行环境)。他的值可能是它的值只可能是 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
};

规范中提供了获取Reference组成部分的方法,比如GetBase和IsPropertyReference

  1. GetBase,返回 reference 的 base value。

GetBase(V). Returns the base value component of the reference V.

  1. IsPropertyReference,如果 base value 是一个对象,就返回true

IsPropertyReference(V). Returns true if either the base value is an object or HasPrimitiveBase(V) is true; otherwise returns false.

  1. GetValue,从Reference类型中获取对应值

    使用方法如下

    var foo = 1;
    var fooReference = {
        base:  EnvironmentRecord,
        name: 'foo',
        strict: false
    };
    
    // 获取对象属性真正的值,foo = 1;
    GetValue(fooReference) // 1;
    

    注意: 调用GetValue返回的是具体的值,而不是一个Reference

如何确定this的值

规范中有描述当函数调用的时候,如果确定this的取值

  1. 计算MemberExpression的结果并赋值给ref

    什么是MemberExpression呢?简单理解就是在函数调用中,()左边的是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
    
  2. 判断ref是不是一个Reference类型

    关键在于看规范如何处理各种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)());
    
    1. test()

    这个例子中,这个例子中,MemberExpression就是test,test是一个标识符,执行的时候会发生什么呢

    11.1.2 Identifier Reference

    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),结果始终是Reference的值,接着看看dentifier Resolution规范

    10.3.1 Identifier Resolution

    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方法的结果,再来看看
    GetIdentifierReference方法

    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
    (词法环境包含环境记录项Environment Record,它是规范用来管理当前作用域下面变量的类型,此处不用理解,知道它返回了这个东东就行了)

    根据这个过程,我们确定MemberExpression test的计算结果是一个Reference类型

        fooReference = {
            "base": LexicalEnvironment,
            "name": "test",
            "strict": false
        }
    

    根据如果ref是Reference,并且base value的值是EnvironmentRecord,那么this的值是ImplicitThisValue(ref)

    根据规范
    (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的结构是undefined,对应到 JavaScript 代码中的 this,还差最后一步:

    Else if thisArg is null or undefined, set the ThisBinding to the global object.

    this 为 undefined,非严格模式下,this 的值为 undefined 的时候,其值会被隐式转换为全局对象。

    由此得知:test()执行时,this = global = window

---


2. foo.bar()

这个例子中,foo.bar是一个属性访问,那么规范中也给出执行属性访问的时候会发生什么
> 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 等于执行 MemberExpression, 在此处为foo.bar的结果,按照前文,是返回一个Reference类型的值

```JavaScript
    var reference_foo_bar = {
        "base": foo, // baseValue 等于 GetValue(baseReference)
        "name": "bar", 
        "strict": false
    }
```

根据`如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么 this 的值为 GetBase(ref)`, IsPropertyReference(ref) 根据base value 是否是一个对象来返回true,

此处IsPropertyReference(ref) 结果为 true,因此

this的值为
this = GetBase(ref),

GetBase 也已经铺垫了,获得 base value 值,这个例子中就是foo,所以 this 的值就是 foo ,示例1的结果就是 2!

词法环境LexicalEnvironment

官方对词法环境的解释如下:

词法环境是一种规范类型,基于 ECMAScript 代码的词法嵌套结构来定义标识符与特定变量和函数的关联关系。词法环境由环境记录(environment record)和可能为空引用(null)的外部词法环境组成。

词法环境由两个部分组成

环境记录(enviroment record),存储变量和函数声明

对外部环境的引用(outer),可以通过它访问外部词法环境

参考链接

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容