在 javascript V8 中,编译阶段是在执行阶段之前发生在函数上,然后执行所有代码还是仅执行全局上下文

Muh*_*sam 1 javascript jit v8 function

我读过很多文章,说编译(创建)阶段首先发生在全局执行上下文中,然后执行代码,当调用函数时,创建阶段然后再次开始该函数,然后执行,这真的是发生了什么吗?为什么创建阶段没有发生在所有代码中,首先包括函数内的变量,然后执行所有代码,因为像这样,创建阶段是执行阶段本身的一部分,引擎在执行之前不知道函数内有哪些变量阶段 另外,如果是这样,为什么这样的事情会在不先登录到控制台的情况下给出错误

console.log('First No Error')

function Error() {
  let a = 2
  console.log(z)
}

Error()
Run Code Online (Sandbox Code Playgroud)

它给出了参考错误,因为 z 没有定义而没有登录到控制台(无错误),为什么会发生这种情况,因为引擎不应该知道函数内部存在错误,直到它只在最后一行执行。

我想知道函数内部已知什么,并且可以在执行函数本身之前使用它(即使它只是内存中没有实际数据的引用以及何时成为内存中的实际数据)。

jmr*_*mrk 5

(V8 开发人员在此。)

编译(创建)阶段

这是两件不同的事情。“创建阶段”是一些人为了向其他人(比如你)解释 JavaScript 引擎的作用而提出的概念。如果您发现它更令人困惑而不是有帮助,您可能应该将反馈直接给他们:-)

“编译”是引擎内部的实现细节:某些引擎可能会将 JavaScript 源代码编译为字节码或机器代码或两者,其他引擎可能不会;JavaScript 语言规范对此没有意见。现代浏览器中的 JavaScript 引擎都会进行各种形式的编译和重新编译;细节取决于每个引擎,并且会不时发生变化。在基于编译思想构建的引擎中,编译必须在执行之前发生(因为编译的结果将被执行),但多长时间并不重要:它可能发生在第一次执行之前,或者很久以前了。

JavaScript 规范确实要求引擎在看到代码时立即报告某些错误(“早期错误”)。因此,引擎必须立即查看所有代码,至少要找到此类错误。但这与编译任何东西都不一样。(这console.log(z)不是早期错误的例子。)

JavaScript 引擎喜欢将任何不需要的工作推迟到以后,以保持快速启动。让网站加载速度更快是一种更好的用户体验,并且由于页面加载通常只涉及页面的某些资源(例如:仅调用某些 JS 函数,仅显示某些图像),这是浏览器加速的一种方式页面加载仅执行加载所需的操作:诸如编译那些仅稍后调用的函数以及下载那些仅稍后显示的图像之类的工作可以推迟到实际需要时为止。

它给出了参考错误,因为 z 没有定义而没有登录到控制台(无错误)首先为什么会发生这种情况

事实并非如此;在引发 ReferenceError 之前记录“First No Error”。尝试一下看看!

我想知道函数内部已知什么,并且可以在函数本身执行之前使用它。

当相应的代码运行时,将创建对象并初始化变量。定义函数时,可以引用函数外部(词法)作用域中的任何变量。例如:

function f1() {
  console.log(a);  // This will be fine.
  console.log(b);  // This will be an error (at execution time).
  console.log(c);  // This will be an error (at execution time).
  console.log(d);  // This will log 'undefined'.
}

// This is in f1's outer scope, so f1 can use it.
// For better readability, I would recommend to define variables like `a`
// before defining the functions that use them (like f1), but that's not
// a JavaScript requirement, just a recommendation for human readers.
var a = 42;

function f2() {
  var b = 123;  // This is not in f1's outer (lexical) scope.
  f1();
}
f2();

// This is in f1's outer scope, but only created after f1 is called.
// Contrary to `var` variables, `let` variables are not hoisted to the
// beginning of their scope, so are (sort of) "invisible" before.
let c = 77;
// f1 will be able to see the existence of this variable, but its value
// will only be set after the call (when execution reaches this point here),
// so within f1 it will be `undefined`.
var d = 88;
Run Code Online (Sandbox Code Playgroud)