如果JavaScript是一种解释型语言,如何提升工作? [英] How does hoisting work if JavaScript is an interpreted language?

查看:195
本文介绍了如果JavaScript是一种解释型语言,如何提升工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对解释器的理解是它逐行执行程序,我们可以看到即时结果,不像转换代码的编译语言,然后执行它。

My understanding of an interpreter is that it executes program line by line and we can see the instant results, unlike compiled languages which convert code, then executes it.

我的问题是,在Javascript中,解释器如何知道变量在程序中的某处被声明并将其记录为 undefined

My question is, in Javascript, how does interpreter come to know that a variable is declared somewhere in the program and logs it as undefined?

请考虑以下计划:

function do_something() {
  console.log(bar); // undefined (but in my understanding about an interpreter, it should be throwing error like variable not declared)
  var bar = 111;
  console.log(bar); // 111
}

隐含理解为:

function do_something() {
  var bar;
  console.log(bar); // undefined
  bar = 111;
  console.log(bar); // 111
}

这是如何工作的?

推荐答案

如果你在表面上想到它,这个' var hoisting'的概念是一个令人困惑的问题。你必须深入研究语言本身的运作方式。 JavaScript是ECMAScript的一种实现,是一种解释型语言,这意味着您编写的所有代码都被送入另一个程序,而该程序依次解释代码,根据源代码的某些部分调用某些函数。

This concept of 'var hoisting' is quite a confusing one if you think of it on the surface. You have to delve into how the language itself works. JavaScript, which is an implementation of ECMAScript, is an interpreted language, meaning all the code you write is fed into another program that in turn, interprets the code, calling certain functions based on parts of your source code.

例如,如果你写:

function foo() {}

解释器一旦满足你的函数声明,就会调用自己调用的函数 FunctionDeclarationInstantiation 创建函数。解释器不是将JavaScript编译为本机机器代码,而是在读取JavaScript代码的每个部分时执行自己按需的C,C ++和机器代码。它并不一定意味着逐行,所有解释都意味着不会发生编译到机器代码中。执行机器代码的单独程序会读取您的代码并动态执行该机器代码。

The interpreter, once it meets your function declaration, will call a function of its own called FunctionDeclarationInstantiation that creates the function. Instead of compiling JavaScript into native machine code, the interpreter executes C, C++, and machine code of its own 'on demand' as each part of your JavaScript code is read. It does not necessarily mean line-by-line, all interpreted means it that no compilation into machine code happens. A separate program that executes machine code reads your code and executes that machine code on the fly.

如何使用 var 声明提升或任何声明,是解释器首先读取所有代码而不执行任何实际代码。它分析代码并将其分成块,称为词汇环境根据ECMAScript 2015语言规范

How this has to with var declaration hoisting or any declaration for that matter, is that the interpreter first reads through all your code once without executing any actual code. It analyzes the code and separates it into chunks, called lexical environment. Per the ECMAScript 2015 Language Specification:


8.1词汇环境



A 词汇环境是一种规范类型,用于根据ECMAScript代码的词法嵌套结构定义标识符与特定变量和函数的关联。词汇环境包括环境记录和对外部词汇环境的可能为空的引用。通常,词汇环境与ECMAScript代码的某些特定语法结构相关联,例如 FunctionDeclaration BlockStatement Catch 子句 TryStatement 并且每次评估此类代码时都会创建一个新的词法环境。

8.1 Lexical Environments

A Lexical Environment is a specification type used to define the association of Identifiers to specific variables and functions based upon the lexical nesting structure of ECMAScript code. A Lexical Environment consists of an Environment Record and a possibly null reference to an outer Lexical Environment. Usually a Lexical Environment is associated with some specific syntactic structure of ECMAScript code such as a FunctionDeclaration, a BlockStatement, or a Catch clause of a TryStatement and a new Lexical Environment is created each time such code is evaluated.

环境记录记录在其关联的词汇环境范围内创建的标识符绑定。它被称为Lexical Environment的EnvironmentRecord

An Environment Record records the identifier bindings that are created within the scope of its associated Lexical Environment. It is referred to as the Lexical Environment’s EnvironmentRecord

在执行任何代码之前,解释器会遍历您的代码并针对每个词法结构,例如函数声明,新块等,创建了一个新的词法环境。在这些词汇环境中,环境记录记录在该环境中声明的所有变量,它们的值以及有关该环境的其他信息。这是允许JavaScript管理变量范围,变量查找链,值等的原因。

Before any code is executed, the interpreter goes through your code and for every lexical structure, such as a function declaration, a new block, etc, a new lexical environment is created. And in those lexical environments, an environment record records all the variables declared in that environment, their value, and other information about that environment. That's what allows for JavaScript to manage variable scope, variable lookup chains, this value, etc.

每个词汇环境与 代码领域相关联

Each lexical environment is associated with a code realm:


8.2 Code Realms



在评估之前,所有ECMAScript代码都必须与 Realm 相关联。从概念上讲,领域包含一组内部对象,一个ECMAScript全局环境,在该全局环境范围内加载的所有ECMAScript代码,以及其他相关的状态和资源。

8.2 Code Realms

Before it is evaluated, all ECMAScript code must be associated with a Realm. Conceptually, a realm consists of a set of intrinsic objects, an ECMAScript global environment, all of the ECMAScript code that is loaded within the scope of that global environment, and other associated state and resources.

您编写的每个JavaScript / ECMAScript代码部分在实际执行任何代码之前都与领域相关联。每个领域都包含与领域相关的特定代码段所使用的内在值,领域的 this 对象,领域的词汇环境等等。

Every section of JavaScript/ECMAScript code you write is associated with a realm before any of the code is actually executed. Each realm consists of the intrinsic values used by the specific section of code associated with the realm, the this object for the realm, a lexical environment for the realm, among other things.

这意味着在执行代码之前会分析代码的每个词汇部分。然后创建一个领域,其中包含有关的所有信息那组代码。源,执行它需要什么变量,声明了哪些变量,这个是什么等等。在 var 声明,创建一个领域,当你定义一个像你在这里所做的那样的函数时:

This means each lexical part of your code is analyzed before executing. Then a realm is created that houses all the information on that set of code. The source, what variables are needed to execute it, which variables have been declared, what this is, etc. In the case of var declarations, a realm is created, when you define a function like you did here:

function do_something() {
  console.log(bar); // undefined
  var bar = 111;
  console.log(bar); // 111
}

此处, FunctionDeclaration 创建一个与新境界相关的新词汇环境。创建词法环境时,解释器会分析代码并查找所有声明。那些声明首先在该词汇环境的最开始处理,因此函数的顶部:

Here, a FunctionDeclaration creates a new lexical environment, associated with a new realm. When a lexical environment is created, the interpreter analyzes the code and finds all declarations. Those declarations are then first processed at the very beginning of that lexical environment, thus the 'top' of the function:


13.3.2变量声明



var 语句声明范围为正在运行的执行上下文的VariableEnvironment Var变量在包含 Lexical Environment <时创建/ a>被实例化并在创建时被初始化为未定义。

因此,每当实例化词汇环境时(创建) ),创建所有 var 声明,初始化为 undefined 。这意味着它们在任何代码执行之前被处理,位于词汇环境的顶部:

Thus, whenever a lexical environment is instantiated (created), all the var declarations are created, initialized to undefined. That means they are processed before any code is executed, at the 'top' of the lexical environment:

var bar; //Processed and declared first
console.log(bar);
bar = 111;
console.log(bar);

然后,在所有之后分析您的JavaScript代码,它最终被执行。因为声明是先处理的,所以声明它(并初始化为 undefined ),给你 undefined

Then, after all your JavaScript code is analyzed, it is finally executed. Because the declaration was processed first, it is declared (and initialized to undefined) giving you undefined.

提升真的有点用词不当。 Hoist意味着声明直接移动到当前词法环境的顶部,而是在执行之前分析代码;什么都没动。

Hoist is kind of a misnomer really. Hoist implies that the declarations are moved directly to the top of the current lexical environment, but instead the code is analyzed before execution; nothing is moved.

注意: const 以相同的方式行事且也被吊起但这不起作用:

Note: let and const act in the same way and are also hoisted but this won't work:

function do_something() {
  console.log(bar); //ReferenceError
  let bar = 111;
  console.log(bar);
}

这将为尝试访问未初始化的变量提供ReferenceError。即使 const 声明被提升,规范明确声明您无法访问它们在初始化之前,不像 var

This will give you a ReferenceError for trying to access an uninitialized variable. Even though let and const declarations are hoisted, the specification explicitly states that you cannot access them before they are initialized, unlike var:


13.3.1 Let和Const声明



const 声明定义范围为正在运行的执行上下文的LexicalEnvironment 。变量是在包含词汇环境时创建的实例化但在评估变量的 LexicalBinding 之前可能无法以任何方式访问。

13.3.1 Let and Const Declarations

let and const declarations define variables that are scoped to the running execution context’s LexicalEnvironment. The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated.

因此,在正式初始化变量之前,无论是未定义还是任何其他值,都无法访问变量。这意味着你似乎无法在声明之前访问它,就像你可以用 var 一样。

Thus, you can't access the variable until it is formally initialized, whether to undefined or any other value. That means you can't seemingly 'access it before it's declared' like you can with var.

这篇关于如果JavaScript是一种解释型语言,如何提升工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆