let和const为什么不能在变量声明前赋值?
Why can't assignment be done before the variable declaration with let and const?
我在多个网站(如 w3schools)上读到,提升是“将所有声明移动到当前范围顶部的行为”。
对于let
和const
,变量被提升但未初始化。
我理解为什么以下代码不起作用,因为 name
对我们没有访问价值。
console.log(name);
let name = "hi";
但为什么我们不能在实际声明之前为 name
赋值,即使 name
已经被声明(提升)?
name = "hi";
let name;
console.log(name);
上面的代码和下面的是不是一样,
let name;
name = "hi";
console.log(name);
因为它们被明确设计为不允许这样做,因为这通常是编程错误。
let
和 const
是 提升的,但这只是提升的绑定声明。 (松散地,“绑定”意味着“变量”[或常量或参数......具有我们用来保存值的名称的东西]。)绑定不会初始化直到稍后,当let
或 const
语句是在代码的逐步执行中到达的。您不能使用未初始化的绑定(以任何方式),这就是您收到错误的原因。
相比之下,var
声明 和 初始化都被提升; var
绑定用值 undefined
初始化。如果在var
(var a = 42
)上有初始化值,后面在逐步执行代码时,到var
语句时,该部分被视为简单赋值(a = 42
)。使用 let
和 const
,这不仅仅是简单的赋值,它是绑定的初始化,允许它被使用。
下面是一个具体示例,说明 let
如何提升声明而不是初始化,以及为什么它有助于防止编程错误:
let a = 1;
function foo() {
a = 2; // <=== Which `a` should be assigned to?
console.log(a);
// code
// code
// code
// code
// code
// code
// code
// code
let a = 3;
console.log(a);
}
foo();
在那段代码中,foo
顶部的赋值似乎应该赋给外部 a
,因为(据我们所知,自上而下阅读)没有其他 a
在范围内。但是有,因为foo
最下面的let
吊了。赋值时出错,因为内部 a
未初始化。
相比之下,var
没有错误,但很容易混淆哪个a
分配在foo
的顶部。
您在评论中表示您仍然不理解声明但未初始化绑定的含义。我认为“初始化”的两个(略微)含义 1 让你在这里感到困惑(当我进入这个东西时他们让我感到困惑),所以让我们稍微改变一下术语。
绑定有一个与之关联的标志,说明它们是否可以使用。我们称它为 usable
标志:usable = true
表示可以使用绑定,usable = false
表示不能。使用该术语,上面的例子是这样处理的:
创建脚本的执行上下文时:
- 其中所有顶级声明的绑定已创建:
let a = 1;
的 let a
部分创建了一个名为 a
的绑定,其 usable
标志设置为 false
(尚不能使用) .
- 函数声明 (
function foo() { }
) 创建了一个名为 foo
的绑定,其 usable
标志设置为 true
(可以使用),其值设置为 undefined
.
- 上下文中的函数声明通过创建它们定义的函数并将它们分配给绑定来处理。所以
foo
得到它的函数值。
在代码的逐步执行中遇到let a = 1;
语句时,它做了两件事:它把usable
标志设置为true
(可以使用)并将 a
的值设置为 1
.
当调用 foo
并创建调用的执行上下文时,将创建顶级声明的绑定:
- 名为
a
的绑定由 let a = 3;
创建,其 usable
标志设置为 false
(尚不能使用)。
当代码一步步执行到a = 2;
语句时,a
解析为内部a
绑定( foo
中的一个,由 let a = 3;
声明),但该绑定的 usable
标志是 false
,因此尝试使用它会引发错误。
如果我们没有a = 2;
语句,所以没有抛出错误,然后当逐步代码执行到let a = 3;
语句时,它会做两件事:将usable
标志设置为true
(可以使用)并设置[的值=27=] 到 3
.
这里 foo
更新了一些评论:
function foo() {
// The local `a` is created but marked `usable` = `false`
a = 2; // <=== Throws error because `a`'s `usable` is `false`
console.log(a);
let a = 3; // <=== If there weren't an error above, this would set
// `usable` to `true` and the value of `a` to `3`
console.log(a);
}
¹ “我认为“初始化”的两个(轻微)含义在这里让您感到困惑...” 我指的两个含义是:
- “初始化”绑定(使其可用,将
usable
设置为 true
),并单独
- “正在初始化”,如设置绑定的初始值。
它们是不同的东西。
我在多个网站(如 w3schools)上读到,提升是“将所有声明移动到当前范围顶部的行为”。
对于let
和const
,变量被提升但未初始化。
我理解为什么以下代码不起作用,因为 name
对我们没有访问价值。
console.log(name);
let name = "hi";
但为什么我们不能在实际声明之前为 name
赋值,即使 name
已经被声明(提升)?
name = "hi";
let name;
console.log(name);
上面的代码和下面的是不是一样,
let name;
name = "hi";
console.log(name);
因为它们被明确设计为不允许这样做,因为这通常是编程错误。
let
和 const
是 提升的,但这只是提升的绑定声明。 (松散地,“绑定”意味着“变量”[或常量或参数......具有我们用来保存值的名称的东西]。)绑定不会初始化直到稍后,当let
或 const
语句是在代码的逐步执行中到达的。您不能使用未初始化的绑定(以任何方式),这就是您收到错误的原因。
相比之下,var
声明 和 初始化都被提升; var
绑定用值 undefined
初始化。如果在var
(var a = 42
)上有初始化值,后面在逐步执行代码时,到var
语句时,该部分被视为简单赋值(a = 42
)。使用 let
和 const
,这不仅仅是简单的赋值,它是绑定的初始化,允许它被使用。
下面是一个具体示例,说明 let
如何提升声明而不是初始化,以及为什么它有助于防止编程错误:
let a = 1;
function foo() {
a = 2; // <=== Which `a` should be assigned to?
console.log(a);
// code
// code
// code
// code
// code
// code
// code
// code
let a = 3;
console.log(a);
}
foo();
在那段代码中,foo
顶部的赋值似乎应该赋给外部 a
,因为(据我们所知,自上而下阅读)没有其他 a
在范围内。但是有,因为foo
最下面的let
吊了。赋值时出错,因为内部 a
未初始化。
相比之下,var
没有错误,但很容易混淆哪个a
分配在foo
的顶部。
您在评论中表示您仍然不理解声明但未初始化绑定的含义。我认为“初始化”的两个(略微)含义 1 让你在这里感到困惑(当我进入这个东西时他们让我感到困惑),所以让我们稍微改变一下术语。
绑定有一个与之关联的标志,说明它们是否可以使用。我们称它为 usable
标志:usable = true
表示可以使用绑定,usable = false
表示不能。使用该术语,上面的例子是这样处理的:
创建脚本的执行上下文时:
- 其中所有顶级声明的绑定已创建:
let a = 1;
的let a
部分创建了一个名为a
的绑定,其usable
标志设置为false
(尚不能使用) .- 函数声明 (
function foo() { }
) 创建了一个名为foo
的绑定,其usable
标志设置为true
(可以使用),其值设置为undefined
.
- 上下文中的函数声明通过创建它们定义的函数并将它们分配给绑定来处理。所以
foo
得到它的函数值。
- 其中所有顶级声明的绑定已创建:
在代码的逐步执行中遇到
let a = 1;
语句时,它做了两件事:它把usable
标志设置为true
(可以使用)并将a
的值设置为1
.当调用
foo
并创建调用的执行上下文时,将创建顶级声明的绑定:- 名为
a
的绑定由let a = 3;
创建,其usable
标志设置为false
(尚不能使用)。
- 名为
当代码一步步执行到
a = 2;
语句时,a
解析为内部a
绑定(foo
中的一个,由let a = 3;
声明),但该绑定的usable
标志是false
,因此尝试使用它会引发错误。如果我们没有
a = 2;
语句,所以没有抛出错误,然后当逐步代码执行到let a = 3;
语句时,它会做两件事:将usable
标志设置为true
(可以使用)并设置[的值=27=] 到3
.
这里 foo
更新了一些评论:
function foo() {
// The local `a` is created but marked `usable` = `false`
a = 2; // <=== Throws error because `a`'s `usable` is `false`
console.log(a);
let a = 3; // <=== If there weren't an error above, this would set
// `usable` to `true` and the value of `a` to `3`
console.log(a);
}
¹ “我认为“初始化”的两个(轻微)含义在这里让您感到困惑...” 我指的两个含义是:
- “初始化”绑定(使其可用,将
usable
设置为true
),并单独 - “正在初始化”,如设置绑定的初始值。
它们是不同的东西。