6

为 JavaScript 中的每个函数创建一个新的执行上下文。

运行以下代码时,内存中存在多少个执行上下文?请注意,Bar未调用函数。

function Foo () {

  function Bar() {}

}

Foo();

此外,何时创建执行上下文?在评估时还是运行时?

4

4 回答 4

5

当您创建一个函数时,它们会在运行时编译。该函数在您调用它们时被调用。

让我稍微解释一下:

您可以拥有任意数量的函数上下文,并且每个函数调用都会创建一个新上下文。

//Global Context
var helloWorld = "hello world!";
function foo(){//execution context
  function bar(){//execution context
   console.log('bar');
  }
}
foo();

因此,在上面的代码中,函数 foo 被调用,并为函数 foo 创建了新的上下文,而 bar 的执行上下文仅在您调用它之后创建,但它已经在运行时编译。

浏览器第一次加载脚本时,默认进入全局执行上下文。如果在全局范围内调用函数,程序的序列流会进入被调用的函数,创建一个新的执行上下文并将该上下文推送到执行堆栈的顶部。

现在让我们详细了解执行上下文:

因此,每次调用函数时,都会创建一个新的执行上下文。对执行上下文的每次调用都有 2 个阶段:

1.创作阶段:

当函数被调用但在它执行内部的任何代码之前是:创建作用域链,创建变量、函数和参数,并确定“this”的值。

2.激活阶段:

赋值、引用函数并执行代码。


现在,让我们对执行上下文有更多的了解

function foo (a, b, c) {
    function z(){alert(‘Z!’);}
    var d = 3;
}
foo(‘foo’,’bar’);

foo() 调用中的 ExecutionContext:第 1 步:创建参数

ExecutionContext: {
    arguments: {
        0: ‘foo’, 1: ‘bar’,
        length: 2, callee: function() //Points to foo function
    }
}

步骤 3a:变量实例化,参数

ExecutionContext: {
    arguments: {
        0: ‘foo’, 1: ‘bar’,
        length: 2, callee: function() //Points to foo function
    },
    a: ‘foo’, b: ‘bar’, c: undefined
}

步骤 3b:变量实例化、函数

ExecutionContext: {
    arguments: {
        0: ‘foo’, 1: ‘bar’,
        length: 2, callee: function() //Points to foo function 
    },
    a: ‘foo’, b: ‘bar’, c: undefined,
    z: function() //Created z() function
}

步骤 3c:变量实例化,变量

ExecutionContext: {
    arguments: {
        0: ‘foo’, 1: ‘bar’,
        length: 2, callee: function() //Points to foo function
    },
    a: ‘foo’, b: ‘bar’, c: undefined,
    z: function(), //Created z() function,
    d: undefined
}

第 4 步:设置此值

ExecutionContext: {
    arguments: {
        0: ‘foo’, 1: ‘bar’,
        length: 2,  callee: function() //Points to foo function
    },
    a: ‘foo’, b: ‘bar’, c: undefined,
    z: function(), //Created z() function,
    d: undefined,
    this: window
}

创建 ExecutionContext 后,函数从第一行开始运行其代码,直到找到返回值或函数结束。每次此代码尝试访问变量时,都会从 ExecutionContext 对象中读取它。

于 2014-11-30T14:51:50.540 回答
5

函数的运行时调用是导致创建执行上下文的原因。因此,在您的示例中,只有一个函数调用,因此只涉及一个执行上下文。

函数的静态(编译时)排列很重要,因为它决定了执行上下文的范围和最终内容。然而,对于创建上下文来说,重要的是对函数的实际调用。(一些较旧的语言使用术语“激活记录”,尽管这可能更适用于基于堆栈的分配。)

您可以阅读规范中有时过于冗长的语言的详细信息,尽管很难为树木辨认出森林。规范是根据正在转移的控制来编写的。函数调用是发生这种情况的一种非常常见的方式,但调用事件处理程序或在<script>浏览器最初加载完整块时调用它也是如此。

于 2014-11-30T14:52:05.843 回答
3

打电话时Foo();

  • 由于调用了单个执行上下文而创建了单个执行上下文function
  • Bar在此过程中,还会创建一个指向该函数的指针。

此外,还有一个默认环境,即您的代码第一次执行的地方,称为全局上下文

于 2014-11-30T14:54:46.427 回答
1

我最好的猜测是它可能取决于您运行代码的环境。

虽然检查 V8 不会为根本没有执行的函数创建执行上下文并不难。

执行的功能 未执行的功能

于 2014-11-30T15:11:25.323 回答