JavaScript中的执行上下文

6
JavaScript 中每个函数都会创建一个新的执行上下文。
当运行以下代码时,有多少执行上下文存在于内存中?请注意,函数Bar未被调用。
function Foo () {

  function Bar() {}

}

Foo();

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

你有什么答案或者猜测吗?这看起来像是一道问答题。 - Pointy
好的,如果没有更多的上下文,它看起来像是一份作业任务,但也可以理解;如果你说不是,那就不是。 :) - Pointy
谢谢你的无端负评?! - Ben Aston
我没有给你的问题投反对票;我会给你点赞,因为这是一个好问题(足够好以至于可以出现在测验中!) - Pointy
可能是为什么这里没有创建执行上下文?的重复问题。 - user663031
显示剩余3条评论
4个回答

5
当您创建函数时,它们会在运行时编译。在调用函数时,将调用该函数。
让我解释一下:
您可以拥有任意数量的函数上下文,并且每个函数调用都会创建一个新的上下文。
//Global Context
var helloWorld = "hello world!";
function foo(){//execution context
  function bar(){//execution context
   console.log('bar');
  }
}
foo();

所以,在上述代码中,函数 foo 被调用,为函数 foo 创建了新的上下文环境并且调用 bar 的执行上下文仅在您调用它时创建,但在运行时已经被编译。
当脚本首次被浏览器加载时,默认进入全局执行上下文。如果在全局范围内调用函数,则程序的流程顺序进入被调用的函数,创建一个新的执行上下文并将其推到执行堆栈的顶部。
现在让我们详细了解一下执行上下文:
所以,每次调用函数都会创建一个新的执行上下文。每个执行上下文的调用有两个阶段:
1.创建阶段: 当函数被调用但在执行任何代码之前:创建作用域链、创建变量、函数和参数,并确定“this”的值。
2.激活阶段: 分配值、引用函数并执行代码。
现在,让我们更加了解执行上下文。请参阅此链接
function foo (a, b, c) {
    function z(){alert(‘Z!’);}
    var d = 3;
}
foo(‘foo’,’bar’);

在foo()调用中的ExecutionContext: 第一步:创建arguments

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
}

第三步b:变量实例化,函数
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之后,函数从第一行开始执行其代码,直到找到一个return语句或函数结束。每次该代码尝试访问变量时,都会从ExecutionContext对象中读取它。


好的,以下代码将创建两个执行上下文:function Foo () { this.bar = (function () {}()) }; new Foo();。如果删除属性 bar,会移除相应的执行上下文吗? - Ben Aston
创建一个函数并不会导致它“停留在堆栈中”。 - Jason S
@JasonS 这是我打字时犯的错误,现在已经更正了。 - Bhojendra Rauniyar

5
函数的运行调用会导致执行上下文的创建。因此,在您的示例中,只有一个函数调用,因此只涉及一个执行上下文。
函数的静态(编译时)排列很重要,因为它决定了作用域和最终执行上下文的内容。但是,对于上下文的创建,实际调用函数才是关键。(一些旧语言使用“激活记录”这个术语,尽管那可能更多地是针对基于堆栈的分配。)
您可以在规范中阅读详细信息,尽管很难看清楚整体框架。该规范是以控制被转移的术语编写的。函数调用是这种情况发生的一种非常常见的方式,但是事件处理程序的调用或浏览器最初加载完整<script>块时的调用也是如此。

3
我认为还有一个全局执行上下文。当 JavaScript 文件被评估时,就会进入这个上下文。毕竟,在评估 Foo 的定义时,必须有一些执行上下文来进行评估。 - Jazzepi
@Jazzepi 是的,那是真的;就我个人而言,我认为它本质上是一个特殊情况;在许多重要方面,它类似于函数调用,但并不完全相同。 - Pointy

3
在调用 Foo(); 时:
  • 由于调用了一个函数,所以会创建一个执行上下文。
  • 同时,在这个过程中还会创建一个指向函数 Bar 的指针。
此外,还有一个默认的环境,在你的代码第一次执行时被称为全局上下文

1
我的最佳猜测是,这可能取决于您运行代码的环境。
尽管检查 V8 是否为未执行的函数创建执行上下文并不难。

Executed function Non-executed function


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接