1. 规范 #

2. 进入全局代码 #

2.1 1.global.js #

src\1.global.js

var a = 1;
function one(c) {
    var b = 2;
    console.log(a, b, c);
}
one(3);

2.2 1.global.run.js #

src\1.global.run.js

/**
var a = 1;
function one(c) {
    var b = 2;
    console.log(a, b, c);
}
one(3);
*/
const LexicalEnvironment = require('./LexicalEnvironment');
const ExecutionContext = require('./ExecutionContext');
const ECStack = require('./ECStack');
//1.将变量环境设置为全局环境 2.将词法环境设置为 全局环境
const globalLexicalEnvironment = LexicalEnvironment.NewObjectEnvironment(global, null);
const globalEC = new ExecutionContext(globalLexicalEnvironment, global);
ECStack.push(globalEC);
//令 env 为当前运行的执行环境的环境变量的 环境记录
let env = ECStack.current.lexicalEnvironment.environmentRecord;
//如果 code 是 eval 代码 ,则令 configurableBindings 为 true,否则令 configurableBindings 为 false。
let configurableBindings = false;
//如果代码是 严格模式下的代码 ,则令 strict 为 true,否则令 strict 为 false。
let strict = false;
//按源码顺序遍历 code,对于每一个 VariableDeclaration 和 VariableDeclarationNoIn 表达式:
//令 dn 为 d 中的标识符。
let dn = 'a';
//以 dn 为参数,调用 env 的 HasBinding 具体方法,并令 varAlreadyDeclared 为调用的结果
let varAlreadyDeclared = env.HasBinding(dn);
//如果 varAlreadyDeclared 为 false,则:
if (!varAlreadyDeclared) {
    //以 dn 和 configurableBindings 为参数,调用 env 的 CreateMutableBinding 具体方法。
    env.CreateMutableBinding(dn, configurableBindings);
    //以 dn、undefined 和 strict 为参数,调用 env 的 SetMutableBinding 具体方法。
    env.SetMutableBinding(dn, undefined, strict);
}
console.log(env.GetBindingValue('a'));

2.3 LexicalEnvironment.js #

src\LexicalEnvironment.js

const DeclarativeEnvironmentRecords = require("./DeclarativeEnvironmentRecords");
const ObjectEnvironmentRecords = require("./ObjectEnvironmentRecords");
class LexicalEnvironment {
    /**
    * 当调用 GetIdentifierReference 抽象运算时
     * @param {*} lex 词法环境
     * @param {*} name  标识符字符串
     * @param {*} strict  布尔型标识
    */
   static GetIdentifierReference(lex, name, strict) {
        //if (!lex) return { name: undefined };
        if (!lex) throw new Error(`ReferenceError: ${name} is not defined`);
        let envRec = lex.environmentRecord;
        let exists = envRec.HasBinding(name);
        if (exists) {
            const value = envRec.GetBindingValue(name);
            return { name: value };
        } else {
            lex = lex.outer;
            return LexicalEnvironment.GetIdentifierReference(lex, name, strict);
        }
    }
    /**
     * 创建新的声明式词法环境
     * @param {*} lexicalEnvironment 父词法环境
     * @returns 
     */
    static NewDeclarativeEnvironment(lexicalEnvironment) {
        let env = new LexicalEnvironment();
        let envRec = new DeclarativeEnvironmentRecords();
        env.environmentRecord = envRec;
        env.outer = lexicalEnvironment;
        return env;
    }
    /**
     * 创建新的对象式词法环境
     * @param {*} lexicalEnvironment 父词法环境
     * @returns 
     */
    static NewObjectEnvironment(object, lexicalEnvironment) {
        let env = new LexicalEnvironment();
        let envRec = new ObjectEnvironmentRecords(object);
        env.environmentRecord = envRec;
        env.outer = lexicalEnvironment;
        return env;;
    }
}
module.exports = LexicalEnvironment;

2.4 DeclarativeEnvironmentRecords.js #

src\DeclarativeEnvironmentRecords.js

const EnvironmentRecord = require('./EnvironmentRecord');
class DeclarativeEnvironmentRecords extends EnvironmentRecord {
    /**
     * 判断环境记录项是否包含对某个标识符的绑定
     * 如果包含该绑定则返回 true,反之返回 false。其中字符串 N 是标识符文本。
     * @param {*} N 名称
     */
    HasBinding(N) {
        let envRec = this;
        return N in envRec;
    }
    /**
     * 在环境记录项中创建一个新的可变绑定
     * @param {*} N  绑定名称
     * @param {*} D  可选参数 D 的值为true,则该绑定在后续操作中可以被删除
     */
    CreateMutableBinding(N, D) {
        //令 envRec 为函数调用时对应的声明式环境记录项
        let envRec = this;
        //执行断言:envRec 没有 N 的绑定。
        console.assert(!this.HasBinding(N));
        //在 envRec 中为 N 创建一个可变绑定,并将绑定的值设置为 undefined
        //如果 D 为 true 则新创建的绑定可在后续操作中通过调用 DeleteBinding 删除
        Object.defineProperty(envRec, N, {
            value: undefined,
            writable: true,
            configurable: D
        });

    }
    /**
     * 环境记录项中设置一个已经存在的绑定的值
     * @param {*} N 绑定名称
     * @param {*} V 绑定的值
     * @param {*} S S 用于指定是否为严格模式 当 S 为 true 并且该绑定不允许赋值时,则抛出一个 TypeError 异常
     */
    SetMutableBinding(N, V, S) {
        //令 envRec 为函数调用时对应的声明式环境记录项
        let envRec = this;
        //执行断言:envRec 必须有 N 的绑定。
        console.assert(this.HasBinding(N));
        //否则该操作会尝试修改一个不可变绑定的值,因此如果 S 的值为 true,则抛出一个 TypeError 异常。
        const propertyDescriptor = Object.getOwnPropertyDescriptor(envRec, N);
        if (S && !propertyDescriptor.writable) {
            throw new Error("TypeError: Assignment to constant variable.");
        }
        //如果 envRec 中 N 的绑定为可变绑定,则将其值修改为 V
        envRec[N] = V;
    }
    /**
     * 返回环境记录项中一个已经存在的绑定的值
     * @param {*} N 绑定的名称
     * @param {*} S 用于指定是否为严格模式 如果 S 的值为 true 并且该绑定不存在或未初始化,则抛出一个 ReferenceError 异常
     */
    GetBindingValue(N, S) {
        //令 envRec 为函数调用时对应的声明式环境记录项
        let envRec = this;
        //执行断言:envRec 必须有 N 的绑定。
        console.assert(this.HasBinding(N));
        //如果 envRec 中 N 的绑定是一个未初始化的不可变绑定,则如果 S 为 false,返回 undefined,否则抛出一个 ReferenceError 异常。
        const V = envRec[N];
        const propertyDescriptor = Object.getOwnPropertyDescriptor(envRec, N);
        if (!propertyDescriptor.uninitialized) {
            if (!S) return V;
            throw new Error(`ReferenceError: Cannot access '${N}' before initialization`);
        }
        //否则返回 envRec 中与 N 绑定的值
        return V;
    }
    /**
     * 从环境记录项中删除一个绑定
     * @param {*} N 绑定的名称 如果 N 指定的绑定存在,将其删除并返回 true。如果绑定存在但无法删除则返回false。如果绑定不存在则返回 true
     */
    DeleteBinding(N) {
        //令 envRec 为函数调用时对应的声明式环境记录项
        let envRec = this;
        if (!this.HasBinding(N)) {
            return true;
        }
        const propertyDescriptor = Object.getOwnPropertyDescriptor(envRec, N);
        if (!propertyDescriptor.configurable) {
            return false;
        }
        delete envRec[N];
        return true;
    }
    /**
     * 当从该环境记录项的绑定中获取一个函数对象并且调用时,该方法返回该函数对象使用的 this 对象的值。
     */
    ImplicitThisValue() {
        return undefined;
    }
    /**
    * 创建一个不可变绑定
    * @param {*} N 名称
    */
    CreateImmutableBinding(N) {
        //令 envRec 为函数调用时对应的声明式环境记录项
        let envRec = this;
        //执行断言:envRec 没有 N 的绑定。
        console.assert(!this.HasBinding(N));
        //在 envRec 中为 N 创建一个不可变绑定,并记录为未初始化
        Object.defineProperty(envRec, N, {
            value: undefined,
            uninitialized: true
        });
    }
    /**
     * 将当前名称为参数 N 的绑定的值修改为参数 V 指定的值
     * @param {*} N 当前名称
     * @param {*} V 绑定的值
     */
    InitializeImmutableBinding(N, V) {
        //令 envRec 为函数调用时对应的声明式环境记录项
        let envRec = this;
        //执行断言:envRec 没有 N 的绑定
        const propertyDescriptor = Object.getOwnPropertyDescriptor(envRec, N);
        console.assert(propertyDescriptor && propertyDescriptor.uninitialized);
        envRec[N] = V;
        propertyDescriptor.uninitialized = true;
    }

}
module.exports = DeclarativeEnvironmentRecords;

2.5 EnvironmentRecord.js #

src\EnvironmentRecord.js

class EnvironmentRecord {

}
module.exports = EnvironmentRecord;

2.6 ObjectEnvironmentRecords.js #

src\ObjectEnvironmentRecords.js

const EnvironmentRecord = require('./EnvironmentRecord');
class ObjectEnvironmentRecords extends EnvironmentRecord {
    constructor(bindings) {
        super();
        this.bindings = bindings;
        this.provideThis = false;
    }
    /**
     * 判断其关联的绑定对象是否有名为 N 的属性
     * 如果包含该绑定则返回 true,反之返回 false。其中字符串 N 是标识符文本。
     * @param {*} N 名称
     */
    HasBinding(N) {
        const envRec = this;
        const bindings = envRec.bindings;
        return bindings.hasOwnProperty(N);
    }
    /**
    * 会在其关联的绑定对象上创建一个名称为 N 的属性
    * @param {*} N  绑定名称
    * @param {*} D  可选参数 D 的值为true,则该绑定在后续操作中可以被删除
    */
    CreateMutableBinding(N, D) {
        //令 envRec 为函数调用时对应的声明式环境记录项
        const envRec = this;
        const bindings = envRec.bindings;
        //执行断言:envRec 没有 N 的绑定。
        console.assert(!bindings.hasOwnProperty(N));
        const configValue = D;
        //在 envRec 中为 N 创建一个可变绑定,并将绑定的值设置为 undefined
        //如果 D 为 true 则新创建的绑定可在后续操作中通过调用 DeleteBinding 删除
        Object.defineProperty(bindings, N, {
            value: undefined,
            enumerable: true,
            configurable: configValue,
            writable: true
        });
    }
    /**
     * 尝试设置其关联的绑定对象中名为 N 的属性的值为 V
     * @param {*} N 绑定名称
     * @param {*} V 绑定的值
     * @param {*} S S 用于指定是否为严格模式 当 S 为 true 并且该绑定不允许赋值时,则抛出一个 TypeError 异常
     */
    SetMutableBinding(N, V, S) {
        //令 envRec 为函数调用时对应的声明式环境记录项
        const envRec = this;
        const bindings = envRec.bindings;
        //执行断言:envRec 必须有 N 的绑定。
        console.assert(this.HasBinding(N));
        //否则该操作会尝试修改一个不可变绑定的值,因此如果 S 的值为 true,则抛出一个 TypeError 异常。
        const propertyDescriptor = Object.getOwnPropertyDescriptor(bindings, N);
        if (S && !propertyDescriptor.writable) {
            throw new Error("TypeError: Assignment to constant variable.");
        }
        //如果 envRec 中 N 的绑定为可变绑定,则将其值修改为 V
        bindings[N] = V;
    }
    /**
     *返回其关联的绑定对象中名为 N 的属性的值
     * @param {*} N 绑定的名称
     * @param {*} S 用于指定是否为严格模式 如果 S 的值为 true 并且该绑定不存在或未初始化,则抛出一个 ReferenceError 异常
     */
    GetBindingValue(N, S) {
        //令 envRec 为函数调用时对应的声明式环境记录项
        const envRec = this;
        const bindings = envRec.bindings;
        //执行断言:envRec 必须有 N 的绑定。
        console.assert(bindings.hasOwnProperty(N), `变量${N}尚未定义`);
        //如果 envRec 中 N 的绑定是一个未初始化的不可变绑定,则如果 S 为 false,返回 undefined,否则抛出一个 ReferenceError 异常。
        const V = bindings[N];
        const propertyDescriptor = Object.getOwnPropertyDescriptor(bindings, N);
        if (!propertyDescriptor.uninitialized) {
            if (!S) return V;
            throw new Error(`ReferenceError: Cannot access '${N}' before initialization`);
        }
        //否则返回 envRec 中与 N 绑定的值
        return V;
    }
    /**
    * 删除其关联的绑定对象上 [[Configurable]] 特性的值为 true 的属性所对应的绑定
    * @param {*} N 绑定的名称 如果 N 指定的绑定存在,将其删除并返回 true。如果绑定存在但无法删除则返回false。如果绑定不存在则返回 true
    */
    DeleteBinding(N) {
        //令 envRec 为函数调用时对应的声明式环境记录项
        const envRec = this;
        const bindings = envRec.bindings;
        if (!bindings.hasOwnProperty(N)) {
            return true;
        }
        const propertyDescriptor = Object.getOwnPropertyDescriptor(bindings, N);
        if (!propertyDescriptor.configurable) {
            return false;
        }
        delete bindings[N];
        return true;
    }
    /**
     * 返回 undefined,除非其 provideThis 标识的值为 true。
     */
    ImplicitThisValue() {
        const envRec = this;
        if (provideThis) {
            return envRec.bindings;
        }
        return undefined;
    }
}
module.exports = ObjectEnvironmentRecords;

2.7 ExecutionContext.js #

src\ExecutionContext.js

class ExecutionContext {
    constructor(lexicalEnvironment, thisBinding) {
        this.variableEnvironment = this.lexicalEnvironment = lexicalEnvironment;
        this.thisBinding = thisBinding;
    }
}
module.exports = ExecutionContext;

2.8 ECStack.js #

src\ECStack.js

class ECStack {
    constructor() {
        this.contexts = [];
    }
    push(EC) {
        this.contexts.push(EC);
    }
    get current() {
        return this.contexts[this.contexts.length - 1];
    }
    pop() {
        this.contexts.pop();
    }
}
module.exports = new ECStack();

3. 注册函数 #

3.1 FunctionDeclaration.js #

src/FunctionDeclaration.js

class FunctionDeclaration {
    static createInstance(fn, FormalParameterList, FunctionBody, Scope) {
        //Strict 为布尔标记
        let Strict = false;
        //按照如下步骤构建函数对象
        //创建一个新的 ECMAScript 原生对象,令 F 为此对象
        let F = { name: fn };
        //依照 8.12 描述设定 F 的除 [[Get]] 以外的所有内部方法
        //设定 F 的 [[Class]] 内部属性为 "Function"。
        F[` [[Class]]`] = Function;
        //设定 F 的 [[Prototype]] 内部属性为 15.3.3.1 指定的标准内置 Function 对象的 prototype 属性
        //F.__proto__=Function.prototype
        F[`[[Prototype]]`] = Function.prototype;
        //依照 15.3.5.4 描述,设定 F 的[[Get]] 内部属性
        //依照 13.2.1 描述,设定 F 的[[Call]] 内部属性
        //依照 13.2.2 描述,设定 F 的[[Construct]] 内部属性
        //依照 15.3.5.3 描述,设定 F 的[[HasInstance]] 内部属性
        //设定 F 的[[Scope]] 内部属性为 Scope 的值
        F[`[[Scope]]`] = Scope;
        //令 names 为一个列表容器,其中元素是以从左到右的文本顺序对应 FormalParameterList 的标识符的字符串。
        let names = FormalParameterList;
        //设定 F 的 [[FormalParameters]] 内部属性为 names
        F[`[[FormalParameters]]`] = names;
        //设定 F 的 [[Code]] 内部属性为 FunctionBody
        F[`[[Code]]`] = FunctionBody;
        //设定 F 的 [[Extensible]] 内部属性为 true。
        F[`[[Extensible]]`] = true;
        //令 len 为 FormalParameterList 指定的形式参数的个数。如果没有指定参数,则令 len 为 0。
        let len = FormalParameterList.length;
        //以参数 "length",属性描述符 {[[Value]]: len, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false},false 调用 F 的 [[DefineOwnProperty]] 内部方法
        Object.defineProperty(F, 'length', { value: len, writable: false, enumerable: false, configurable: false });
        //令 proto 为仿佛使用 new Object() 表达式创建新对象的结果,其中 Object 是标准内置构造器名
        let proto = new Object();
        //以参数 "constructor", 属性描述符 {[[Value]]: F, { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}, false 调用 proto 的 [[DefineOwnProperty]] 内部方法。
        Object.defineProperty(proto, 'constructor', { value: F, writable: true, enumerable: false, configurable: false });
        //以参数 "prototype", 属性描述符 {[[Value]]: proto, { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}, false 调用 F 的 [[DefineOwnProperty]] 内部方法。
        //每个函数都会自动创建一个 prototype 属性,以满足函数会被当作构造器的可能性
        Object.defineProperty(F, 'prototype', { value: proto, writable: true, enumerable: false, configurable: false });
        return F;
    }
}
module.exports = FunctionDeclaration;

3.2 global.run.js #

src\1.global.run.js

/**
var a = 1;
function one(c) {
    var b = 2;
    console.log(a, b,c);
}
one();
*/
const LexicalEnvironment = require('./LexicalEnvironment');
const ExecutionContext = require('./ExecutionContext');
const ECStack = require('./ECStack');
+const FunctionDeclaration = require('./FunctionDeclaration');

//1.将变量环境设置为全局环境 2.将词法环境设置为 全局环境
const globalLexicalEnvironment = LexicalEnvironment.NewObjectEnvironment(global, null);
const globalEC = new ExecutionContext(globalLexicalEnvironment, global);
ECStack.push(globalEC);

//令 env 为当前运行的执行环境的环境变量的 环境记录
let env = ECStack.current.lexicalEnvironment.environmentRecord;
//如果 code 是 eval 代码 ,则令 configurableBindings 为 true,否则令 configurableBindings 为 false。
let configurableBindings = false;
//如果代码是 严格模式下的代码 ,则令 strict 为 true,否则令 strict 为 false。
let strict = false;
//按源码顺序遍历 code,对于每一个 VariableDeclaration 和 VariableDeclarationNoIn 表达式:
//令 dn 为 d 中的标识符。
let dn = 'a';
//以 dn 为参数,调用 env 的 HasBinding 具体方法,并令 varAlreadyDeclared 为调用的结果
let varAlreadyDeclared = env.HasBinding(dn);
//如果 varAlreadyDeclared 为 false,则:
if (!varAlreadyDeclared) {
    //以 dn 和 configurableBindings 为参数,调用 env 的 CreateMutableBinding 具体方法。
    env.CreateMutableBinding(dn, configurableBindings);
    //以 dn、undefined 和 strict 为参数,调用 env 的 SetMutableBinding 具体方法。
    env.SetMutableBinding(dn, undefined, strict);
}
console.log(env.GetBindingValue('a'));

+//按源码顺序遍历 code,对于每一个 FunctionDeclaration 表达式 f:
+//令 fn 为 FunctionDeclaration 表达式 f 中的 标识符
+let fn = 'one';
+//创建函数对象
+//指定 FormalParameterList 为可选参数列表
+let FormalParameterList = ['c'];
+//指定 FunctionBody 为函数体
+let FunctionBody = `
+    var b = 2;
+    console.log(a, b);
+`;
+//指定 Scope 为 词法环境
+let Scope = ECStack.current.lexicalEnvironment;
+//按 第 13 章 中所述的步骤初始化 FunctionDeclaration 表达式 ,并令 fo 为初始化的结果。
+let fo = FunctionDeclaration.createInstance(fn, FormalParameterList, FunctionBody, Scope);
+//以 fn 为参数,调用 env 的 HasBinding 具体方法,并令 argAlreadyDeclared 为调用的结果。
+let argAlreadyDeclared = env.HasBinding(fn);
+if (!argAlreadyDeclared) {
+    env.CreateMutableBinding(fn, configurableBindings);
+} else {
+    //否则如果 env 是全局环境的 环境记录 对象,则
+    //令 go 为全局对象。
+    let go = global;
+    //以 fn 为参数,调用 go 和 [[GetProperty]] 内部方法,并令 existingProp 为调用的结果。
+    let existingProp = Object.getOwnPropertyDescriptor(go, fn);
+    if (existingProp.configurable) {
+        Object.defineProperty(go, fn, { value: undefined, writable: true, enumerable: true, configurable: +configurableBindings });
+        if (!existingProp.writable) {
+            throw new Error(`TypeError`);
+        }
+    }
+}
+env.SetMutableBinding(fn, fo, strict);
+console.log(env.GetBindingValue('one'));

4. 执行全局代码和函数 #

4.1 CreateArgumentsObject.js #

src\CreateArgumentsObject.js

/**
 * Arguments 对象通过调用抽象方法 CreateArgumentsObject 创建,
 * 调用时将以下参数传入:func, names, args, env, strict。
 * @param {*} func  将要执行的函数对象作为 func 参数
 * @param {*} names  将该函数的所有形参名加入一个 List 列表,作为 names 参数
 * @param {*} args 将所有传给内部方法 [[Call]] 的实际参数作为 args 参数
 * @param {*} env 将该函数代码的环境变量作为 env 参数
 * @param {*} strict 将该函数代码是否为严格代码作为strict 参数
 */
function CreateArgumentsObject(func, names, args, env, strict) {
    //令 len 为参数 args 的元素个数
    let len = args.length;
    //令 obj 为一个新建的 ECMAScript 对象
    //按照 8.12 章节中的规范去设定 obj 对象的所有内部方法
    let obj = {};
    //将 obj 对象的内部属性 [[Class]] 设置为 "Arguments"
    obj[`[[Class]]`] = 'Arguments';
    //令 Object 为标准的内置对象的构造函数 (15.2.2)
    obj.constructor = Object;
    //将 obj 对象的内部属性 [[Prototype]] 设置为标准的内置对象的原型对象
    obj[`[[Prototype]]`] = Object.prototype;
    //调用 obj 的内部方法 [[DefineOwnProperty]],将 "length" 传递进去,属性描述符为:{[[Value]]: len, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true},参数为 false
    Object.defineProperty(obj, 'length', {
        value: len, writable: true, enumerable: false, configurable: true
    });
    let indx = len - 1;
    while (indx >= 0) {
        let val = args[indx];
        Object.defineProperty(obj, indx.toString(), { value: val, writable: true, enumerable: true, configurable: true });
        indx = indx - 1;
    }
    return obj;
}
module.exports = CreateArgumentsObject;

4.2 global.run.js #

src\1.global.run.js

/**
var a = 1;
function one(c) {
    var b = 2;
    console.log(a, b,c);
}
one();
*/
const LexicalEnvironment = require('./LexicalEnvironment');
const ExecutionContext = require('./ExecutionContext');
const ECStack = require('./ECStack');
const FunctionDeclaration = require('./FunctionDeclaration');
+const CreateArgumentsObject = require('./CreateArgumentsObject');

//1.将变量环境设置为全局环境 2.将词法环境设置为 全局环境
const globalLexicalEnvironment = LexicalEnvironment.NewObjectEnvironment(global, null);
const globalEC = new ExecutionContext(globalLexicalEnvironment, global);
ECStack.push(globalEC);

//令 env 为当前运行的执行环境的环境变量的 环境记录
let env = ECStack.current.lexicalEnvironment.environmentRecord;
//如果 code 是 eval 代码 ,则令 configurableBindings 为 true,否则令 configurableBindings 为 false。
let configurableBindings = false;
//如果代码是 严格模式下的代码 ,则令 strict 为 true,否则令 strict 为 false。
let strict = false;
//按源码顺序遍历 code,对于每一个 VariableDeclaration 和 VariableDeclarationNoIn 表达式:
//令 dn 为 d 中的标识符。
let dn = 'a';
//以 dn 为参数,调用 env 的 HasBinding 具体方法,并令 varAlreadyDeclared 为调用的结果
let varAlreadyDeclared = env.HasBinding(dn);
//如果 varAlreadyDeclared 为 false,则:
if (!varAlreadyDeclared) {
    //以 dn 和 configurableBindings 为参数,调用 env 的 CreateMutableBinding 具体方法。
    env.CreateMutableBinding(dn, configurableBindings);
    //以 dn、undefined 和 strict 为参数,调用 env 的 SetMutableBinding 具体方法。
    env.SetMutableBinding(dn, undefined, strict);
}
console.log(env.GetBindingValue('a'));//undefined

//按源码顺序遍历 code,对于每一个 FunctionDeclaration 表达式 f:
//令 fn 为 FunctionDeclaration 表达式 f 中的 标识符
let fn = 'one';
//创建函数对象
//指定 FormalParameterList 为可选参数列表
let FormalParameterList = ['c'];
//指定 FunctionBody 为函数体
let FunctionBody = `
    var b = 2;
    console.log(a, b);
`;
//指定 Scope 为 词法环境
let Scope = ECStack.current.lexicalEnvironment;
//按 第 13 章 中所述的步骤初始化 FunctionDeclaration 表达式 ,并令 fo 为初始化的结果。
let fo = FunctionDeclaration.createInstance(fn, FormalParameterList, FunctionBody, Scope);
//以 fn 为参数,调用 env 的 HasBinding 具体方法,并令 argAlreadyDeclared 为调用的结果。
let argAlreadyDeclared = env.HasBinding(fn);
if (!argAlreadyDeclared) {
    env.CreateMutableBinding(fn, configurableBindings);
} else {
    //否则如果 env 是全局环境的 环境记录 对象,则
    //令 go 为全局对象。
    let go = global;
    //以 fn 为参数,调用 go 和 [[GetProperty]] 内部方法,并令 existingProp 为调用的结果。
    let existingProp = Object.getOwnPropertyDescriptor(go, fn);
    if (existingProp.configurable) {
        Object.defineProperty(go, fn, { value: undefined, writable: true, enumerable: true, configurable: configurableBindings });
        if (!existingProp.writable) {
            throw new Error(`TypeError`);
        }
    }
}
env.SetMutableBinding(fn, fo, strict);
//console.log(env.GetBindingValue('one'));//1

+// 给a赋值为1
+env.SetMutableBinding('a', 1);
+console.log(env.GetBindingValue('a'));//1
+//进入函数代码
+//当控制流根据一个函数对象 F、调用者提供的 thisArg 以及调用者提供的 argumentList,进入 函数代码 的执行环境时,执行以下步+骤:
+let thisArg = global;
+let argumentList = [3];
+//以 F 的 [[Scope]] 内部属性为参数调用 NewDeclarativeEnvironment,并令 localEnv 为调用的结果
+let localEnv = LexicalEnvironment.NewDeclarativeEnvironment(fo[`[[Scope]]`]);
+//设词法环境为 localEnv 设变量环境为 localEnv
+let oneExecutionContext = new ExecutionContext(localEnv, thisArg);
+ECStack.push(oneExecutionContext);
+//按 [10.5](#10.5) 描述的方案,使用 函数代码 code 和 argumentList 执行定义绑定初始化步骤
+env = ECStack.current.lexicalEnvironment.environmentRecord;
+configurableBindings = false;
+strict = false;
+//令 func 为通过 [[Call]] 内部属性初始化 code 的执行的函数对象
+let func = fo;
+//令 code 为 F 的 [[Code]] 内部属性的值。
+let code = func[`[[Code]]`];
+//令 names 为 func 的 [[FormalParameters]] 内部属性。
+names = func[`[[FormalParameters]]`];
+let args = [3];
+//令 argCount 为 args 中元素的数量
+let argCount = args.length;
+let n = 0;
+names.forEach(argName => {
+    n += 1;
+    let v = n > argCount ? undefined : args[n - 1];
+    //以 argName 为参数,调用 env 的 HasBinding 具体方法,并令 argAlreadyDeclared 为调用的结果。
+    argAlreadyDeclared = env.HasBinding(argName);
+    if (!argAlreadyDeclared) {
+        env.CreateMutableBinding(argName);
+    }
+    env.SetMutableBinding(argName, v, strict);
+});
+let argumentsAlreadyDeclared = env.HasBinding('arguments');
+if (!argumentsAlreadyDeclared) {
+    let argsObj = CreateArgumentsObject(func, names, args, env, strict);
+    env.CreateMutableBinding('arguments');
+    env.SetMutableBinding('arguments', argsObj);
+}
+
+dn = 'b';
+//以 dn 为参数,调用 env 的 HasBinding 具体方法,并令 varAlreadyDeclared 为调用的结果
+varAlreadyDeclared = env.HasBinding(dn);
+//如果 varAlreadyDeclared 为 false,则:
+if (!varAlreadyDeclared) {
+    //以 dn 和 configurableBindings 为参数,调用 env 的 CreateMutableBinding 具体方法。
+    env.CreateMutableBinding(dn, configurableBindings);
+    //以 dn、undefined 和 strict 为参数,调用 env 的 SetMutableBinding 具体方法。
+    env.SetMutableBinding(dn, undefined, strict);
+}
+env.SetMutableBinding(dn, 2);
+
+console.log(env.GetBindingValue('arguments'));//['3']
+
+console.log(
+    LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'a'),
+    LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'b'),
+    LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'c')
+);

5. 块级作用域 #

5.1 block.js #

var a = 1;
function one(c) {
    var b = 2;
    console.log(a, b, c, e /**,f*/);
    let d = 4;
    {
        let d = 5;
        var e = 6;
        let f = 7;
        console.log(a, b, c, d, e, f);
    }
}
one(3);

5.2 block.run.js #

src\block.run.js

/**
var a = 1;
function one(c) {
    var b = 2;
    console.log(a, b, c, e);
    let d = 4;
    {
        let d = 5;
        var e = 6;
        console.log(a, b, c, d, e);
    }
}
one(3);
*/
const LexicalEnvironment = require('./LexicalEnvironment');
const ExecutionContext = require('./ExecutionContext');
const ECStack = require('./ECStack');
const FunctionDeclaration = require('./FunctionDeclaration');
const CreateArgumentsObject = require('./CreateArgumentsObject');

//1.将变量环境设置为全局环境 2.将词法环境设置为 全局环境
const globalLexicalEnvironment = LexicalEnvironment.NewObjectEnvironment(global, null);
const globalEC = new ExecutionContext(globalLexicalEnvironment, global);
ECStack.push(globalEC);

//令 env 为当前运行的执行环境的环境变量的 环境记录
let env = ECStack.current.lexicalEnvironment.environmentRecord;
//如果 code 是 eval 代码 ,则令 configurableBindings 为 true,否则令 configurableBindings 为 false。
let configurableBindings = false;
//如果代码是 严格模式下的代码 ,则令 strict 为 true,否则令 strict 为 false。
let strict = false;
//按源码顺序遍历 code,对于每一个 VariableDeclaration 和 VariableDeclarationNoIn 表达式:
//令 dn 为 d 中的标识符。
let dn = 'a';
//以 dn 为参数,调用 env 的 HasBinding 具体方法,并令 varAlreadyDeclared 为调用的结果
let varAlreadyDeclared = env.HasBinding(dn);
//如果 varAlreadyDeclared 为 false,则:
if (!varAlreadyDeclared) {
    //以 dn 和 configurableBindings 为参数,调用 env 的 CreateMutableBinding 具体方法。
    env.CreateMutableBinding(dn, configurableBindings);
    //以 dn、undefined 和 strict 为参数,调用 env 的 SetMutableBinding 具体方法。
    env.SetMutableBinding(dn, undefined, strict);
}
console.log(env.GetBindingValue('a'));//undefined

//按源码顺序遍历 code,对于每一个 FunctionDeclaration 表达式 f:
//令 fn 为 FunctionDeclaration 表达式 f 中的 标识符
let fn = 'one';
//创建函数对象
//指定 FormalParameterList 为可选参数列表
let FormalParameterList = ['c'];
//指定 FunctionBody 为函数体
let FunctionBody = `
    var b = 2;
    console.log(a, b);
`;
//指定 Scope 为 词法环境
let Scope = ECStack.current.lexicalEnvironment;
//按 第 13 章 中所述的步骤初始化 FunctionDeclaration 表达式 ,并令 fo 为初始化的结果。
let fo = FunctionDeclaration.createInstance(fn, FormalParameterList, FunctionBody, Scope);
//以 fn 为参数,调用 env 的 HasBinding 具体方法,并令 argAlreadyDeclared 为调用的结果。
let argAlreadyDeclared = env.HasBinding(fn);
if (!argAlreadyDeclared) {
    env.CreateMutableBinding(fn, configurableBindings);
} else {
    //否则如果 env 是全局环境的 环境记录 对象,则
    //令 go 为全局对象。
    let go = global;
    //以 fn 为参数,调用 go 和 [[GetProperty]] 内部方法,并令 existingProp 为调用的结果。
    let existingProp = Object.getOwnPropertyDescriptor(go, fn);
    if (existingProp.configurable) {
        Object.defineProperty(go, fn, { value: undefined, writable: true, enumerable: true, configurable: configurableBindings });
        if (!existingProp.writable) {
            throw new Error(`TypeError`);
        }
    }
}
env.SetMutableBinding(fn, fo, strict);
//console.log(env.GetBindingValue('one'));//1

// 给a赋值为1
env.SetMutableBinding('a', 1);
console.log(env.GetBindingValue('a'));//1
//进入函数代码
//当控制流根据一个函数对象 F、调用者提供的 thisArg 以及调用者提供的 argumentList,进入 函数代码 的执行环境时,执行以下步骤:
let thisArg = global;
let argumentList = [3];
//以 F 的 [[Scope]] 内部属性为参数调用 NewDeclarativeEnvironment,并令 localEnv 为调用的结果
let localEnv = LexicalEnvironment.NewDeclarativeEnvironment(fo[`[[Scope]]`]);
//设词法环境为 localEnv 设变量环境为 localEnv
let oneExecutionContext = new ExecutionContext(localEnv, thisArg);
ECStack.push(oneExecutionContext);
//按 [10.5](#10.5) 描述的方案,使用 函数代码 code 和 argumentList 执行定义绑定初始化步骤
env = ECStack.current.lexicalEnvironment.environmentRecord;
configurableBindings = false;
strict = false;
//令 func 为通过 [[Call]] 内部属性初始化 code 的执行的函数对象
let func = fo;
//令 code 为 F 的 [[Code]] 内部属性的值。
let code = func[`[[Code]]`];
//令 names 为 func 的 [[FormalParameters]] 内部属性。
names = func[`[[FormalParameters]]`];
let args = [3];
//令 argCount 为 args 中元素的数量
let argCount = args.length;
let n = 0;
names.forEach(argName => {
    n += 1;
    let v = n > argCount ? undefined : args[n - 1];
    //以 argName 为参数,调用 env 的 HasBinding 具体方法,并令 argAlreadyDeclared 为调用的结果。
    argAlreadyDeclared = env.HasBinding(argName);
    if (!argAlreadyDeclared) {
        env.CreateMutableBinding(argName);
    }
    env.SetMutableBinding(argName, v, strict);
});
let argumentsAlreadyDeclared = env.HasBinding('arguments');
if (!argumentsAlreadyDeclared) {
    let argsObj = CreateArgumentsObject(func, names, args, env, strict);
    env.CreateMutableBinding('arguments');
    env.SetMutableBinding('arguments', argsObj);
}

dn = 'b';
//以 dn 为参数,调用 env 的 HasBinding 具体方法,并令 varAlreadyDeclared 为调用的结果
varAlreadyDeclared = env.HasBinding(dn);
//如果 varAlreadyDeclared 为 false,则:
if (!varAlreadyDeclared) {
    //以 dn 和 configurableBindings 为参数,调用 env 的 CreateMutableBinding 具体方法。
    env.CreateMutableBinding(dn, configurableBindings);
    //以 dn、undefined 和 strict 为参数,调用 env 的 SetMutableBinding 具体方法。
    env.SetMutableBinding(dn, undefined, strict);
}


+dn = 'e';
+//以 dn 为参数,调用 env 的 HasBinding 具体方法,并令 varAlreadyDeclared 为调用的结果
+varAlreadyDeclared = env.HasBinding(dn);
+//如果 varAlreadyDeclared 为 false,则:
+if (!varAlreadyDeclared) {
+    //以 dn 和 configurableBindings 为参数,调用 env 的 CreateMutableBinding 具体方法。
+    env.CreateMutableBinding(dn, configurableBindings);
+    //以 dn、undefined 和 strict 为参数,调用 env 的 SetMutableBinding 具体方法。
+    env.SetMutableBinding(dn, undefined, strict);
+}
+
+localEnv = LexicalEnvironment.NewDeclarativeEnvironment(ECStack.current.variableEnvironment);
+env = localEnv.environmentRecord;
+dn = 'd';
+//以 dn 为参数,调用 env 的 HasBinding 具体方法,并令 varAlreadyDeclared 为调用的结果
+varAlreadyDeclared = env.HasBinding(dn);
+//如果 varAlreadyDeclared 为 false,则:
+if (!varAlreadyDeclared) {
+    //以 dn 和 configurableBindings 为参数,调用 env 的 CreateMutableBinding 具体方法。
+    env.CreateMutableBinding(dn, configurableBindings);
+    //以 dn、undefined 和 strict 为参数,调用 env 的 SetMutableBinding 具体方法。
+    env.SetMutableBinding(dn, undefined, strict);
+}
+ECStack.current.lexicalEnvironment = localEnv;
+//开始执行one
+ECStack.current.variableEnvironment.environmentRecord.SetMutableBinding('b', 2);
+console.log(
+    'a=' + LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'a').name,
+    'b=' + LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'b').name,
+    'c=' + LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'c').name,
+    'e=' + LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'e').name,
+    //LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'f')
+);
+ECStack.current.variableEnvironment.environmentRecord.SetMutableBinding('d', 4);
+
+localEnv = LexicalEnvironment.NewDeclarativeEnvironment(ECStack.current.variableEnvironment);
+ECStack.current.lexicalEnvironment = localEnv;
+env = localEnv.environmentRecord;
+dn = 'd';
+//以 dn 为参数,调用 env 的 HasBinding 具体方法,并令 varAlreadyDeclared 为调用的结果
+varAlreadyDeclared = env.HasBinding(dn);
+//如果 varAlreadyDeclared 为 false,则:
+if (!varAlreadyDeclared) {
+    //以 dn 和 configurableBindings 为参数,调用 env 的 CreateMutableBinding 具体方法。
+    env.CreateMutableBinding(dn, configurableBindings);
+    //以 dn、undefined 和 strict 为参数,调用 env 的 SetMutableBinding 具体方法。
+    env.SetMutableBinding(dn, undefined, strict);
+}
+dn = 'f';
+//以 dn 为参数,调用 env 的 HasBinding 具体方法,并令 varAlreadyDeclared 为调用的结果
+varAlreadyDeclared = env.HasBinding(dn);
+//如果 varAlreadyDeclared 为 false,则:
+if (!varAlreadyDeclared) {
+    //以 dn 和 configurableBindings 为参数,调用 env 的 CreateMutableBinding 具体方法。
+    env.CreateMutableBinding(dn, configurableBindings);
+    //以 dn、undefined 和 strict 为参数,调用 env 的 SetMutableBinding 具体方法。
+    env.SetMutableBinding(dn, undefined, strict);
+}
+ECStack.current.lexicalEnvironment.environmentRecord.SetMutableBinding('d', 5);
+ECStack.current.variableEnvironment.environmentRecord.SetMutableBinding('e', 6);
+ECStack.current.lexicalEnvironment.environmentRecord.SetMutableBinding('f', 7);
+console.log(
+    'a=' + LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'a').name,
+    'b=' + LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'b').name,
+    'c=' + LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'c').name,
+    'd=' + LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'd').name,
+    'e=' + LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'e').name,
+    'f=' + LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'f').name
+);

6. 闭包 #

6.1 closure.js #

var a = 1;
function one(c) {
    var b = 2;
   function two() {
       console.log(a,b,c);
   }
   return two;
}
var two = one(3);
two();

6.2 closure.run.js #

closure.run.js

/**
var a = 1;
function one(c) {
    var b = 2;
    return function two() {
        console.log(a, b, c);
    }
}
var two = one(3);
two();
*/
const LexicalEnvironment = require('./LexicalEnvironment');
const ExecutionContext = require('./ExecutionContext');
const ECStack = require('./ECStack');
const FunctionDeclaration = require('./FunctionDeclaration');
const CreateArgumentsObject = require('./CreateArgumentsObject');

//1.将变量环境设置为全局环境 2.将词法环境设置为 全局环境
const globalLexicalEnvironment = LexicalEnvironment.NewObjectEnvironment(global, null);
const globalEC = new ExecutionContext(globalLexicalEnvironment, global);
ECStack.push(globalEC);

//令 env 为当前运行的执行环境的环境变量的 环境记录
let env = ECStack.current.lexicalEnvironment.environmentRecord;
//如果 code 是 eval 代码 ,则令 configurableBindings 为 true,否则令 configurableBindings 为 false。
let configurableBindings = false;
//如果代码是 严格模式下的代码 ,则令 strict 为 true,否则令 strict 为 false。
let strict = false;
//按源码顺序遍历 code,对于每一个 VariableDeclaration 和 VariableDeclarationNoIn 表达式:
//令 dn 为 d 中的标识符。
let dn = 'a';
//以 dn 为参数,调用 env 的 HasBinding 具体方法,并令 varAlreadyDeclared 为调用的结果
let varAlreadyDeclared = env.HasBinding(dn);
//如果 varAlreadyDeclared 为 false,则:
if (!varAlreadyDeclared) {
    //以 dn 和 configurableBindings 为参数,调用 env 的 CreateMutableBinding 具体方法。
    env.CreateMutableBinding(dn, configurableBindings);
    //以 dn、undefined 和 strict 为参数,调用 env 的 SetMutableBinding 具体方法。
    env.SetMutableBinding(dn, undefined, strict);
}
//console.log(env.GetBindingValue('a'));//undefined
+dn = 'two';
+//以 dn 为参数,调用 env 的 HasBinding 具体方法,并令 varAlreadyDeclared 为调用的结果
+varAlreadyDeclared = env.HasBinding(dn);
+//如果 varAlreadyDeclared 为 false,则:
+if (!varAlreadyDeclared) {
+    //以 dn 和 configurableBindings 为参数,调用 env 的 CreateMutableBinding 具体方法。
+    env.CreateMutableBinding(dn, configurableBindings);
+    //以 dn、undefined 和 strict 为参数,调用 env 的 SetMutableBinding 具体方法。
+    env.SetMutableBinding(dn, undefined, strict);
+}
//console.log(env.GetBindingValue(dn));//undefined

//按源码顺序遍历 code,对于每一个 FunctionDeclaration 表达式 f:
//令 fn 为 FunctionDeclaration 表达式 f 中的 标识符
let fn = 'one';
//创建函数对象
//指定 FormalParameterList 为可选参数列表
let FormalParameterList = ['c'];
//指定 FunctionBody 为函数体
let FunctionBody = `
    var b = 2;
    console.log(a, b);
`;
//指定 Scope 为 词法环境
let Scope = ECStack.current.lexicalEnvironment;
//按 第 13 章 中所述的步骤初始化 FunctionDeclaration 表达式 ,并令 fo 为初始化的结果。
let fo = FunctionDeclaration.createInstance(fn, FormalParameterList, FunctionBody, Scope);
//以 fn 为参数,调用 env 的 HasBinding 具体方法,并令 argAlreadyDeclared 为调用的结果。
let argAlreadyDeclared = env.HasBinding(fn);
if (!argAlreadyDeclared) {
    env.CreateMutableBinding(fn, configurableBindings);
} else {
    //否则如果 env 是全局环境的 环境记录 对象,则
    //令 go 为全局对象。
    let go = global;
    //以 fn 为参数,调用 go 和 [[GetProperty]] 内部方法,并令 existingProp 为调用的结果。
    let existingProp = Object.getOwnPropertyDescriptor(go, fn);
    if (existingProp.configurable) {
        Object.defineProperty(go, fn, { value: undefined, writable: true, enumerable: true, configurable: configurableBindings });
        if (!existingProp.writable) {
            throw new Error(`TypeError`);
        }
    }
}
env.SetMutableBinding(fn, fo, strict);
//console.log(env.GetBindingValue('one'));//1

// 给a赋值为1
env.SetMutableBinding('a', 1);
//进入函数one代码
//当控制流根据一个函数对象 F、调用者提供的 thisArg 以及调用者提供的 argumentList,进入 函数代码 的执行环境时,执行以下步骤:
let thisArg = global;
//以 F 的 [[Scope]] 内部属性为参数调用 NewDeclarativeEnvironment,并令 localEnv 为调用的结果
let localEnv = LexicalEnvironment.NewDeclarativeEnvironment(fo[`[[Scope]]`]);
//设词法环境为 localEnv 设变量环境为 localEnv
let oneExecutionContext = new ExecutionContext(localEnv, thisArg);
ECStack.push(oneExecutionContext);
//按 [10.5](#10.5) 描述的方案,使用 函数代码 code 和 argumentList 执行定义绑定初始化步骤
env = ECStack.current.lexicalEnvironment.environmentRecord;
configurableBindings = false;
strict = false;
//令 func 为通过 [[Call]] 内部属性初始化 code 的执行的函数对象
let func = fo;
//令 code 为 F 的 [[Code]] 内部属性的值。
let code = func[`[[Code]]`];
//令 names 为 func 的 [[FormalParameters]] 内部属性。
names = func[`[[FormalParameters]]`];
let args = [3];
//令 argCount 为 args 中元素的数量
let argCount = args.length;
let n = 0;
names.forEach(argName => {
    n += 1;
    let v = n > argCount ? undefined : args[n - 1];
    //以 argName 为参数,调用 env 的 HasBinding 具体方法,并令 argAlreadyDeclared 为调用的结果。
    argAlreadyDeclared = env.HasBinding(argName);
    if (!argAlreadyDeclared) {
        env.CreateMutableBinding(argName);
    }
    env.SetMutableBinding(argName, v, strict);
});
let argumentsAlreadyDeclared = env.HasBinding('arguments');
if (!argumentsAlreadyDeclared) {
    let argsObj = CreateArgumentsObject(func, names, args, env, strict);
    env.CreateMutableBinding('arguments');
    env.SetMutableBinding('arguments', argsObj);
}

dn = 'b';
//以 dn 为参数,调用 env 的 HasBinding 具体方法,并令 varAlreadyDeclared 为调用的结果
varAlreadyDeclared = env.HasBinding(dn);
//如果 varAlreadyDeclared 为 false,则:
if (!varAlreadyDeclared) {
    //以 dn 和 configurableBindings 为参数,调用 env 的 CreateMutableBinding 具体方法。
    env.CreateMutableBinding(dn, configurableBindings);
    //以 dn、undefined 和 strict 为参数,调用 env 的 SetMutableBinding 具体方法。
    env.SetMutableBinding(dn, undefined, strict);
}

//开始执行
env.SetMutableBinding(dn, 2);


+//按源码顺序遍历 code,对于每一个 FunctionDeclaration 表达式 f:
+//令 fn 为 FunctionDeclaration 表达式 f 中的 标识符
+fn = 'two';
+//创建函数对象
+//指定 FormalParameterList 为可选参数列表
+FormalParameterList = [];
+//指定 FunctionBody 为函数体
+FunctionBody = `
+    console.log(a, b, c);
+`;
+//指定 Scope 为 词法环境
+Scope = ECStack.current.lexicalEnvironment;
+//按 第 13 章 中所述的步骤初始化 FunctionDeclaration 表达式 ,并令 fo 为初始化的结果。
+fo = FunctionDeclaration.createInstance(fn, FormalParameterList, FunctionBody, Scope);
+//退出one
+ECStack.pop();
+env = ECStack.current.lexicalEnvironment.environmentRecord;
+//以 fn 为参数,调用 env 的 HasBinding 具体方法,并令 argAlreadyDeclared 为调用的结果。
+argAlreadyDeclared = env.HasBinding(fn);
+if (!argAlreadyDeclared) {
+    env.CreateMutableBinding(fn, configurableBindings);
+} else {
+    //否则如果 env 是全局环境的 环境记录 对象,则
+    //令 go 为全局对象。
+    let go = global;
+    //以 fn 为参数,调用 go 和 [[GetProperty]] 内部方法,并令 existingProp 为调用的结果。
+    let existingProp = Object.getOwnPropertyDescriptor(go, fn);
+    if (existingProp.configurable) {
+        Object.defineProperty(go, fn, { value: undefined, writable: true, enumerable: true, configurable: +configurableBindings });
+        if (!existingProp.writable) {
+            throw new Error(`TypeError`);
+        }
+    }
+}
+env.SetMutableBinding(fn, fo, strict);
+//执行two
+//当控制流根据一个函数对象 F、调用者提供的 thisArg 以及调用者提供的 argumentList,进入 函数代码 的执行环境时,执行以下步+骤:
+thisArg = global;
+//以 F 的 [[Scope]] 内部属性为参数调用 NewDeclarativeEnvironment,并令 localEnv 为调用的结果
+localEnv = LexicalEnvironment.NewDeclarativeEnvironment(fo[`[[Scope]]`]);
+//设词法环境为 localEnv 设变量环境为 localEnv
+oneExecutionContext = new ExecutionContext(localEnv, thisArg);
+ECStack.push(oneExecutionContext);
+//按 [10.5](#10.5) 描述的方案,使用 函数代码 code 和 argumentList 执行定义绑定初始化步骤
+env = ECStack.current.lexicalEnvironment.environmentRecord;
+configurableBindings = false;
+strict = false;
+//令 func 为通过 [[Call]] 内部属性初始化 code 的执行的函数对象
+func = fo;
+//令 code 为 F 的 [[Code]] 内部属性的值。
+code = func[`[[Code]]`];
+//令 names 为 func 的 [[FormalParameters]] 内部属性。
+names = func[`[[FormalParameters]]`];
+args = [3];
+//令 argCount 为 args 中元素的数量
+argCount = args.length;
+n = 0;
+names.forEach(argName => {
+    n += 1;
+    let v = n > argCount ? undefined : args[n - 1];
+    //以 argName 为参数,调用 env 的 HasBinding 具体方法,并令 argAlreadyDeclared 为调用的结果。
+    argAlreadyDeclared = env.HasBinding(argName);
+    if (!argAlreadyDeclared) {
+        env.CreateMutableBinding(argName);
+    }
+    env.SetMutableBinding(argName, v, strict);
+});
+argumentsAlreadyDeclared = env.HasBinding('arguments');
+if (!argumentsAlreadyDeclared) {
+    let argsObj = CreateArgumentsObject(func, names, args, env, strict);
+    env.CreateMutableBinding('arguments');
+    env.SetMutableBinding('arguments', argsObj);
+}
+console.log(
+    'a=' + LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'a').name,
+    'b=' + LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'b').name,
+    'c=' + LexicalEnvironment.GetIdentifierReference(ECStack.current.lexicalEnvironment, 'c').name
+);

10. 可执行代码与执行环境 #

10.1 可执行代码类型 #

10.1.1 全局代码 #

console.log('global');

10.1.2 Eval 代码 #

eval('console.log("hello")');

10.1.3 函数代码 #


function one() {
    console.log('one');
}
one();

const sum = new Function("a,b", "return a+b");
console.log(sum(1, 2));

10.2 词法环境 #

let a = 1;
function one() {
    let a = 2;
    console.log(a);
    try {
        let a = 3;
        console.log(a);
        throw new Error('wrong');
    } catch (error) {
        let a = 4;
        console.log(a);
        with ({}) {
            let a = 5;
            console.log(a);
        }
    }
}
one();

10.2.1 环境记录项 #

10.2.1.1 声明式环境记录项 #
10.2.1.2 对象式环境记录项 #

10.2.2 词法环境的运算 #

10.2.3 全局环境 #

10.2.3.1 全局对象 #

10.3 执行环境 #

组件 作用目的
词法环境 指定一个词法环境对象,用于解析该执行环境内的代码创建的标识符引用
变量环境 指定一个词法环境对象,其环境数据用于保存由该执行环境内的代码通过变量表达式和函数表达式创建的绑定
This绑定 指定该执行环境内的 ECMA 脚本代码中 this 关键字所关联的值

10.3.1 标识符解析 #

10.4 建立执行环境 #

10.4.1 进入全局代码 #

10.4.1.1 初始化全局执行环境 #

10.5 定义绑定初始化 #