变量声明是否与变量的绑定相同?

时间:2018-06-17 16:55:18

标签: javascript computer-science

MDN documentation声明:

  

让绑定在包含的(块)范围的顶部创建   声明,通常称为“吊装”。与变量不同   用var声明,它将以undefined值开头,let   在评估定义之前,不会初始化变量。   在初始化之前访问变量会导致a   引发ReferenceError。该变量位于“时间死区”   块的开始直到处理初始化。

nullptr绑定”是否仅仅引用了nullptrlet的{​​{1}}和let,或者只是创建了存储空间(这与关键字没有关系??

以前我认为变量关键字和变量名一起包含一个声明,但在我最近询问的question中,回答者说它们实际上是初始化。

3 个答案:

答案 0 :(得分:3)

我很抱歉在撰写MDN段落时使用了两个不同的术语。出于文章中的所有目的,"变量"和#34;绑定"应该被理解为同一件事。但是,让我们详细说明。

variable declaration创建变量(作为抽象实体)。它告诉编译器它应该引入一个新变量,并且还可以告诉它有关名称,要保持的类型,初始值,范围等(取决于语言)。在JS中,有不同类型的声明可以执行不同的操作,例如

  • var有一个名称,一个可选的初始化程序和特定于var
  • 的作用域规则
  • function有一个(有时是可选的)名称,该值始终为已知且已知为函数
  • const有一个名称,一个必需的初始化程序,应该是不可变的,并且有词法作用域
  • ...

binding是变量名与变量实体的关联,例如" x是指用class x"声明的变量。这样的绑定取决于范围,即在每个不同的范围内都有不同的绑定,因此标识符x可能在不同的范围内引用不​​同的事物。 鉴于JavaScript的作用域规则,变量声明还会导致在各自的作用域中创建自身的绑定。

因此,绑定是使名称可用的原因。这就是我所说的" let绑定是在范围顶部创建的"。它与现有变量,为其分配内存或初始化无关。

答案 1 :(得分:2)

声明只是说存在某些东西。在JavaScript中,您可以声明变量,函数和(最近的)类。

在某些语言(例如C,C ++)中,可以在没有定义的情况下声明。例如:

// this declares a function exists with a given signature, but doesn't define its implementation
void someFunction();

someFunction(); // here we call the function, since we know it exists

// here we define the function, which we have to do at some point
void someFunction() { /* ... */ }

这种模式在现代语言中不常见,其中声明和定义倾向于组合,但是理解区别,因为你的问题主要是关于术语。

可以声明变量,但它们没有定义。

let b; // we declare that there's a variable 'b'

相反,您可以分配变量:

b = 5; // assignment
let c = 6; // declaration and assignment in one statement

计算机科学中绑定的概念有many forms。例如,当您在代码中键入foo时,绑定是确定应使用哪个变量/函数/类型/ ...的行为。在JavaScript中,这非常简单,但在某些语言中它可能会变得非常毛茸茸(由于重载决策等原因)。

但是我不相信MDN在讨论让绑定时的含义。我认为这是“让声明和转让”的简写,正如我们上面所见。

无论如何,我不会过分担心这个词。从您引用的段落中了解的最重要的一点是,letconstvar的更严格版本,在最新版本的语言中引入,以解决陷阱和意外问题从var的工作方式。

  

以前我认为变量关键字和变量名一起包含一个声明

你是对的。

var a;
var b = 1;
let c;
let c = 2;
const d = 3;

这些都是变量的声明(即使const技术变量不能改变,或者更准确地说,它们不能重新分配。

只是var有点草率和令人惊讶。

你可以在同一范围内多次声明一个var:

var a = 1;
var a = 2;

这不适用于let

let a = 1;
let a = 2; // SyntaxError: Identifier 'a' has already been declared

var的范围界定也是令人惊讶的:

for (var i = 0; i < 10; i++)
{
    var inner = 1;
}

console.log(inner); // prints 1 even though you might think this would be an error

或者更糟:

for (var i = 0; i < 10; i++)
{
    for (var i = 0; i < 10; i++)
    {
        console.log('hello');
    }
}

您可能会认为这会打印hello 100次(10 * 10),但实际上只打印了10次,因为两个循环都使用相同的变量。这是一种语言应该真正阻止的程序员错误。如果该代码使用let i代替,则会产生语法错误。

对于提升,您可以将其视为所有var声明已移至包含函数的顶部。

function foo()
{
    doThing();
    var i = 0;
    doSomethingElse();
    for (var j = 0; j < 10; j++)
    {
        var k = 10;
    }
}

即使您可以编写代码,但它的行为就像您写的那样:

function foo()
{
    var i; // all declarations hoisted to top of containing function scope
    var j;
    var k;

    doThing();
    i = 0;
    doSomethingElse();
    for (j = 0; j < 10; j++)
    {
        k = 10;
    }
}

这就是你可以写的原因:

i = 10;
var i;

var在代码中向上移动,因此其行为如下:

var i;
i = 10;

您可以认为let没有被移动。因此,在声明它之前引用它是错误的。

答案 2 :(得分:0)

这里要理解的主要事情是js引擎实际上在两种不同的情况下(以及其他所有语句都访问let语句,但这里特别重要)。在解析期间访问它一次,它生成AST并分析范围和变量。它还为每个范围创建变量列表。现在,当代码执行时,引擎第二次访问语句(或者更频繁地访问语句中的循环/函数/无论如何),现在最终初始化变量并为其赋值。所以&#34;吊装&#34;基本上只是由于解析/执行阶段引起的,引擎知道变量在执行期间到达声明语句之前就存在,因为它之前已经解析过它。

  

&#34;让绑定&#34;引用(let和const的提升)只是关键字let,或者只是创建存储空间(与关键字没有关系)?

关键字实际上会在范围记录中生成一个条目,然后在执行期间将其转换为存储空间。另一方面,语句本身会在执行期间导致初始化。所以当声明发生时很难说,这就是一个单词的问题。常见的是说

该变量在第10行宣布

在该块中声明

so wether&#34;声明&#34;是指陈述或范围分配取决于你:)

  

回答者说他们实际上是初始化。

实际上,回答者更喜欢称之为&#34;初始化&#34;而不是&#34;声明&#34;不要混淆读者,但实际上,人类语言的混淆并不像机器语言那样明确。