JS 变量提升与暂时性死区

177 阅读3分钟

一、变量提升

在JS中,变量提升(Hoisting)是指声明变量时,变量声明会被提升到其作用域的顶部,但是赋值不会被提升。

在JS中有三种变量不同的变量声明方式,各有特点:

1.1 var 声明变量

在JS中,使用 var 关键字声明的变量会存在变量提升(hoisting)现象。

变量可以在声明前使用,其值为 undefind

因为变量提升导致,变量和函数的声明会被提升到作用域的顶部

console.log(a);  // 输出 undefind
var a = 123;

 function fn() {
     console.log(b);  // 输出 undefind
     var b = 456;
 }

1.2 let 和 const 声明变量

ES6(ECMAScript2015)明确规定,当在代码块({})中使用 let 和 const 声明变量时,这些变量会被限制在代码块内,即所谓的块级作用域

let 和 const 声明的变量必须在声明后使用,否则会报错。

由此 let 和 const 还引入了一个概念“暂时性死区”,即在变量的声明之前,尝试访问变量会导致报错。

优点

(1)let 和 const 在处理变量时更加安全和可控,避免了在变量声明前就尝试访问它们可能导致的错误和不可预测行为。 (2)块级作用域的概念也提供了更好的局部变量管理,有助于减少作用域内的冲突意外的全局变量

二、暂时性死区

暂时性死区(Temporal Dead Zone,简称TDZ)是JS中的一个概念,指代码块内,如果引用了某个变量但是在该变量声明之前,就会产生一个错误。

是为了防止变量在声明之前被无意中使用,造成意外行为。

function fn() {
    console.log(a);  // 这里会抛出ReferenceError
    let a = 1;
}
fn()

上述代码中,在 let a = 1; 声明前,a 就已经处于暂时性死区,所以,使用 console.log(a); 尝试访问变量 a 时,会抛出 ReferenceError 异常

因为,a 在这个时刻还没有被定义

使用var声明的变量,没有暂时性死区

2.1 var 声明的变量

拥有变量提升,没有暂时性死区

2.2 let 声明的变量

没有变量提升,拥有暂时性死区,作用于块级作用域

{
    // console.log(temp, 1); // 报错 ReferenceError
    let temp;
    console.log(temp, 2);  // undefined 2
    temp = 666;
    console.log(temp, 3);  // 666 3
}

2.2 const 声明的变量

拥有暂时性死区,作用域块级作用域

声明的是常量,定义的时候就需要赋值,并且之后不能改变

{
    // console.log(temp); // 报错 ReferenceError
    const temp = 123;

    console.log(temp);  // 123
    temp = 456;
    console.log(temp);  // 报错 TypeError
}

const 声明的变量(常量)有如下特点

  • const 声明的变量是常量,声明的值在声明后就不能被改变。如果尝试改变 const 变量的值,会抛出 TypeError 错误。
  • const 声明的变量必须立刻初始化。如果尝试声明一个未初始化的 const 变量,JS会抛出 SyntaxError 错误。
  • 对于基础类型的数据(数字、字符串、布尔值等),使用 const 声明后不能改变它们的值。
  • 对于引用类型的数据(对象、数组),使用 const 声明的变量,可以通过修改它们的属性或元素来实现某处种程度的修改,而不需要修改变量本身引用的对象或数组。

综上所述,虽然 const 声明的变量在 JS 中看起来像是不可变的,但实际上它们并不是完全不可变的量.

如果需要完全不可变的变量,可以使用其他方法,可以使用 Object.freeze() 方法来冻结对象

{
    const a = { name: '张三' };
    a.name = '李四';
    const b = { name: '张三' };
    Object.freeze(b);
    b.name = '王五';
    console.log(a.name);  // 李四
    console.log(b.name);  // 张三
}