let到底会不会造成变量提升

本文探讨了JavaScript中let声明的变量是否会发生提升现象,并解释了let与var声明变量的区别。通过ECMAScript规范和V8引擎行为说明,在块作用域内let声明的变量虽然会被提升,但在初始化前使用会触发暂时性死区。

let到底会不会造成变量提升呢?
关于这个问题,大家可以先在心中想想现在自己的答案,我们继续往下看:

今天有个群里有人提了这个问题,大部分人都说不会,但是在我的印象里是觉得会的,但是太多不同的声音,让我也开始怀疑自己,到底会不会提升呢?

于是我又翻起了红宝书,在红宝书(第四版)第26页,有这么一句话:

let 与 var 的另一个重要的区别,就是 let 声明的变量不会在作用域中被提升。

但是在往后翻翻,在第92页又写了这么一句话:

严格来讲,let 在 JavaScript 运行时中也会被提升,但由于“暂时性死区”(temporal dead zone)的 缘故,实际上不能在声明之前使用 let 变量。因此,从写 JavaScript 代码的角度说,let 的提升跟 var 是不一样的。

所以到底存不存在提升呢?

我们先了解下什么是暂时性死区:
通过let或者const声明的变量会在进入块级作用域的时被创建,但是在该变量没有赋值之前,引用该变量JavaScript引擎会抛出错误。这就是“暂时性死区”。

我们再来看看ecma中对let和const的定义

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. A variable defined by a LexicalBinding with an Initializer is assigned the value of its Initializer’s AssignmentExpression when the LexicalBinding is evaluated, not when the variable is created. If a LexicalBinding in a let declaration does not have an Initializer the variable is assigned the value undefined when the LexicalBinding is evaluated.

我们重点看第二句:
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 声明的变量,在编译阶段全都被存放到变量环境里面了。通过 let 声明的变量,在编译阶段会被存放到词法环境(Lexical Environment)中。

我们再来看这一段代码:

function test(){
    console.log(a);
    let a = 1;
}

执行test的时候,编译阶段a已经在内存中,为什么提前访问不了?这主要是因为V8虚拟机做了限制,虽然a在内存中,但是当你在let a 之前访问a时,根据ECMAScript定义,虚拟机会阻止的访问。

最后总结下:
在块作用域内,let声明的变量被提升,但变量只是创建被提升,初始化并没有被提升,在初始化之前使用变量,就会形成一个暂时性死区。

### let 和 const 声明的变量是否存在变量提升JavaScript 中,`let` 和 `const` 声明的变量与 `var` 声明的变量存在显著差异。虽然 `let` 和 `const` 声明的变量在技术上也存在“变量提升”的现象,但它们的行为同于 `var` 声明的变量[^2]。具体表现为,`let` 和 `const` 声明的变量会被提升到作用域顶部,但在初始化之前访问这些变量会导致引用错误(ReferenceError),这是因为它们处于“暂时性死区”(Temporal Dead Zone, TDZ)[^5]。 以下是具体的分析: #### 1. 变量提升行为 - **`var` 声明的变量**:`var` 声明的变量会被提升到其作用域的顶部,但赋值操作不会提升。因此,在声明之前访问变量时,返回值为 `undefined`[^4]。 ```javascript console.log(foo); // undefined var foo = 2; ``` - **`let` 和 `const` 声明的变量**:尽管 `let` 和 `const` 声明的变量也会被提升,但在初始化之前访问它们会导致引用错误。这是因为这些变量在声明之前位于“暂时性死区”中[^3]。 ```javascript console.log(bar); // ReferenceError: Cannot access 'bar' before initialization let bar = 3; ``` #### 2. 暂时性死区 `let` 和 `const` 声明的变量在声明之前无法访问,这种特性被称为“暂时性死区”。任何尝试在声明之前访问这些变量的操作都会抛出错误。这一特性旨在避免因变量提升导致的意外行为。 #### 3. 块级作用域 与 `var` 同,`let` 和 `const` 声明的变量具有块级作用域(block scope)。这意味着它们仅在声明它们的代码块内可见,而不会泄漏到外部作用域。 ```javascript if (true) { let baz = 4; } console.log(baz); // ReferenceError: baz is not defined ``` #### 4. `const` 的特殊性 `const` 声明的变量除了具备 `let` 的所有特性外,还要求必须在声明时进行初始化,并且其值能被重新赋值[^4]。 ```javascript const qux; // SyntaxError: Missing initializer in const declaration const qux = 5; qux = 6; // TypeError: Assignment to constant variable ``` ### 示例对比 以下代码展示了 `var`、`let` 和 `const` 在变量提升方面的差异: ```javascript console.log(a); // undefined console.log(b); // ReferenceError: Cannot access 'b' before initialization console.log(c); // ReferenceError: c is not defined var a = 1; let b = 2; const c = 3; ``` ### 总结 `let` 和 `const` 声明的变量确实存在变量提升的现象,但它们在声明之前可访问,这种行为通过“暂时性死区”来实现。相比之下,`var` 声明的变量在声明之前可以访问,但其值为 `undefined`[^5]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值