MDN documentation声明:
让绑定在包含的(块)范围的顶部创建 声明,通常称为“吊装”。与变量不同 用var声明,它将以undefined值开头,let 在评估定义之前,不会初始化变量。 在初始化之前访问变量会导致a 引发ReferenceError。该变量位于“时间死区” 块的开始直到处理初始化。
“nullptr
绑定”是否仅仅引用了nullptr
和let
的{{1}}和let
,或者只是创建了存储空间(这与关键字没有关系??
以前我认为变量关键字和变量名一起包含一个声明,但在我最近询问的question中,回答者说它们实际上是初始化。
答案 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在讨论让绑定时的含义。我认为这是“让声明和转让”的简写,正如我们上面所见。
无论如何,我不会过分担心这个词。从您引用的段落中了解的最重要的一点是,let
和const
是var
的更严格版本,在最新版本的语言中引入,以解决陷阱和意外问题从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;不要混淆读者,但实际上,人类语言的混淆并不像机器语言那样明确。