首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么不能用let和const在变量声明之前完成赋值?

为什么不能用let和const在变量声明之前完成赋值?
EN

Stack Overflow用户
提问于 2021-07-04 09:17:06
回答 1查看 565关注 0票数 3

我在多个网站(比如w3schools)上读到,提升是“将所有声明移到当前范围顶部的行为”。

对于letconst,变量是悬挂的,但没有初始化。

我理解为什么下面的代码不能工作,因为name对我们来说没有价值。

代码语言:javascript
复制
console.log(name);
let name = "hi";

但是为什么我们不能在name的实际声明之前给它赋值,即使name已经被声明(提升)?

代码语言:javascript
复制
name = "hi";
let name;
console.log(name);

上述代码不与以下代码相同吗?

代码语言:javascript
复制
let name;
name = "hi";
console.log(name);

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-07-04 09:21:55

因为它们的明确设计是不允许这样做的,因为这通常是一个编程错误。

letconst都是悬挂的,但这只是绑定的声明而已。(松散地说,"binding“意为”变量“或常量或parameter...things,其名称用于保存值。)绑定直到稍后在逐步执行代码时到达letconst语句时才初始化。您不能使用未初始化的绑定(以任何方式),这也是您获得错误的原因。

相反,对于var,声明和初始化都是悬挂的;var绑定是用值undefined初始化的。如果var (var a = 42)上有一个初始化值,那么稍后在逐步执行代码时到达var语句时,该部分将被视为简单赋值(a = 42)。对于letconst,它不仅仅是简单的赋值,而是绑定的初始化,允许使用它。

下面是一个具体的例子,说明let如何提升声明,而不是初始化,以及为什么它有助于防止编程错误:

代码语言:javascript
复制
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。但确实存在,因为位于let底部的foo已被悬挂。执行分配时会出现错误,因为内部a没有初始化。

相反,对于var,没有错误,但是很容易混淆在foo顶部分配了哪个a

在注释中,您表示仍然不理解声明绑定而不是初始化绑定意味着什么。我认为“初始化”的两个(轻微)含义在这里让你感到困惑(当我进入这个话题时,它们让我感到困惑),所以让我们稍微修改一下术语。

绑定有一个与它们相关联的标志,说明是否可以使用它们。让我们称它为usable标志:usable = true表示可以使用绑定,usable = false表示不能使用。

创建脚本的执行上下文时的

代码语言:javascript
复制
1. Bindings for all top level declarations within it are created: 
    - The `let a` part of `let a = 1;` creates a binding called `a` with its `usable` flag set to `false` (can't be used yet).
    - The function declaration (`function foo() { }`) creates a binding called `foo` with its `usable` flag set to `true` (can b eused) and its value set to `undefined`.
代码语言:javascript
复制
1. Function declarations within the context are processed by creating the functions they define and assigning them to the binding. So `foo` gets its function value.

当在逐步执行代码过程中遇到

  1. 语句时,它会执行两件事:将usable标志设置为true (可以使用),并将a的值设置为true

当调用

  1. 并创建调用的执行上下文时,将为顶级声明创建绑定:

代码语言:javascript
复制
1. A binding called `a` is created by `let a = 3;` with its `usable` flag set to `false` (can't be used yet).

当在代码的逐步执行中到达

  1. 语句时,a解析为内部a绑定( foo中的绑定,由let a = 3;声明),但是绑定的usable标志是false,因此尝试使用它会引发错误。< code >H 257G 258

  1. If我们没有a = 2;语句,所以没有抛出错误,然后当逐步执行代码到达let a = 3;语句时,它将做两件事:将usable标志设置为true (可以使用),并将a的值设置为3.

下面是带有一些注释的foo更新:

代码语言:javascript
复制
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);
}

“我认为”初始化“的两个(略)含义在这里混淆了你。”我指的两个意思是:

  1. "Initializing“绑定(使其可用,将usable设置为true)和separately
  2. "Initializing”设置绑定的初始值。

它们是不同的东西。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68243230

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档