新一帅帅

文章 评论 浏览 31

新一帅帅 2022-05-04 13:51:27

分析第二段代码

var scope = "global scope";
function checkscope() {
  var scope = "local scope";
  function f() {
    return scope;
  }
  return f;
}
checkscope()();

1.执行全局代码,创建全局执行上下文,全局上下文被压入执行上下文栈:

ECStack = [
   globalContext
]

2.开始执行代码,全局上下文初始化:

globalContext = {
     VO: [ global ],
     Scope: [ globalContext.VO ],
     this: globalContext.VO
}

3.初始化的同时,checkscope函数被创建,保存作用域链到内部属性[[scope]]:

checkscope.[[scope]] = [
      globalContext.VO
];

4.开始执行checkscope函数,创建checkscope函数执行上下文,并将checkscope函数上下文压入执行上下文栈:

ECStack = [
    checkscopeContext,
    globalContext
];

5.checkscope函数上下文初始化:

  1. 复制函数 [[scope]] 属性创建作用域链,
  2. 用 arguments 创建活动对象,
  3. 初始化活动对象,即加入形参、函数声明、变量声明,
  4. 将活动对象压入 checkscope 函数作用域链顶端。
checkscopeContext = {
        AO: {
            arguments: {
                length: 0
            },
            scope: undefined,
            f: reference to function f(){}
        },
        Scope: [AO, globalContext.VO],
        this: undefined
}

初始化的同时, f函数被创建,保存作用域链到 f函数的内部属性[[scope]]:

f.[[scope]] = [checkscopeContext.AO, globalContext.VO]

6.checkscope函数执行,随着函数的执行,修改AO的值,所以此时checkscopeContext变更为:

checkscopeContext = {
        AO: {
            arguments: {
                length: 0
            },
            scope: "local scope",
            f: reference to function f(){}
        },
        Scope: [AO, globalContext.VO],
        this: checkscopeContext.AO
}

接着返回了f函数.

7.checkscope 函数执行完毕,checkscope 执行上下文从执行上下文栈中弹出:

ECStack = [
    globalContext
];

8.开始执行f 函数,创建f函数执行上下文,并将f函数上下文压入执行上下文栈:

ECStack = [
    fContext,
    globalContext
];

9.f函数上下文初始化:

  1. 复制函数 [[scope]] 属性创建作用域链,
  2. 用 arguments 创建活动对象,
  3. 初始化活动对象,即加入形参、函数声明、变量声明,
  4. 将活动对象压入 f 函数 作用域链顶端。
fContext = {
        AO: {
            arguments: {
                length: 0
            }
        },
        Scope: [AO, checkscopeContext.AO, globalContext.VO],
        this: undefined
}

10.f函数执行,沿着作用域链查找scope 的值,找到并返回了scope.

可是当 f 函数执行的时候,checkscope 函数上下文已经被销毁了(即从执行上下文栈中被弹出),怎么还会读取到 checkscope 作用域下的 scope 值呢?

这是因为 checkscope 函数执行上下文初始化时,f 函数同时被创建,保存作用域链到 f 函数的内部属性[[scope]],所以即使checkscope函数执行完毕,被弹出执行上下文栈,但是checkscopeContext.AO 依然存在于 f 函数的内部属性[scope]]中:

f.[[scope]] = [checkscopeContext.AO, globalContext.VO]

所以在f 函数执行的时候仍然可以通过 f 函数的作用域链能找到scope.所以这里就产生了闭包:

  • 即使创建它的上下文已经销毁,它仍然存在(比如,内部函数从父函数中返回)
  • 在代码中引用了自由变量

11.f 函数执行完毕,f 执行上下文从执行上下文栈中弹出:

ECStack = [
    globalContext
];

JavaScript 深入之执行上下文

新一帅帅 2022-05-04 12:38:15

应该是 a.b.c.da['b']['c']['d'] 性能高点,后者还要考虑 [ ] 中是变量的情况,再者,从两种形式的结构来看,显然编译器解析前者要比后者容易些,自然也就快一点。
下图是两者的 AST 对比:

第 65 题: a.b.c.d 和 a['b']['c']['d'] 哪个性能更高?

更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文