JavaScript 中的提升:一个可能欺骗你的简单概念

提升是 JavaScript 面试中最常见的问题之一,通常被认为是适合初学者的概念。然而,它的行为可能具有欺骗性,甚至会让经验丰富的开发人员陷入陷阱。

什么是提升?

JavaScript 中的提升是一种行为,在代码执行之前,在编译阶段将变量和函数声明移动到其包含范围(脚本或函数)的顶部。

仅提升声明,而不提升初始化或赋值。

提升对于变量、函数和类有不同的行为。让我们一一了解它们。

变量提升

var 关键字的提升

  • 使用 var 声明的变量被提升,但其初始化仍然存在。
  • console.log(a); // Output: undefined (declaration hoisted, not initialisation)
    var a = 5;
    console.log(a); // Output: 5

    let 和 const 关键字的提升

  • 用 let 和 const 声明的变量也会被提升,但由于“暂时死区”,它们在声明之前无法访问。
  • console.log(b); // ReferenceError: Cannot access 'b' before initialisation
    console.log(c); // ReferenceError: Cannot access 'c' before initialisation
    let b = 10;
    const c = 'alphabet';

    函数提升

  • 函数声明被完全提升,这意味着您可以在函数定义之前调用它。
  • greet(); // Output: Hello!
    function greet() {
        console.log("Hello!");
    }
  • 函数表达式(使用 var、let 或 const)未完全提升;只有变量声明被提升,而不是赋值。
  • sayHello(); // TypeError: sayHello is not a function
    var sayHello = function() {
         console.log("Hello!");
    };

    类提升

  • 类的提升方式与函数不同。在声明之前使用类将导致 ReferenceError。
  • const obj = new MyClass(); // ReferenceError: Cannot access 'MyClass' before initialisation
    class MyClass {
        constructor() {
            console.log("Hello from MyClass!");
        }
    }

    值得记住

  • 提升发生在定义变量或函数的范围内。在函数内声明的变量将被提升至该函数范围的顶部。
  • 对于 let 和 const,从代码块开始到遇到变量声明为止,存在一个“暂时死区”。在此期间,访问变量将引发 ReferenceError。
  • 一些值得遵循的最佳实践

  • 在范围顶部声明变量和函数以避免混淆和错误。
  • 避免在现代 JavaScript 中使用 var;最好使用 let 和 const。
  • 了解函数声明和表达式之间的区别,以避免错误。
  • 额外信息

    什么是暂时死区(TDZ)?

  • 暂时死区 (TDZ) 是变量作用域开始和代码中声明之间的时间。在此期间,访问变量将引发 ReferenceError。
  • TDZ 为什么存在?

  • 可预测的行为
  • TDZ 确保变量在正确声明和初始化之前不会被使用。
  • 常见错误的预防
  • 如果没有 TDZ,变量在初始化之前可能会具有未定义或非预期的值,从而导致难以调试的问题。
  • 鼓励声明式代码
  • 通过要求在使用之前声明变量,TDZ 可以促进代码更清晰、更结构化。
  • 提升可能看起来像一个简单的概念,但它的细微差别甚至会让经验丰富的开发人员措手不及。通过了解声明在后台的处理方式,您可以编写更干净、更可预测的代码,并解决那些棘手的面试问题。请记住,掌握基础知识是成为 JavaScript 专业人士的第一步!祝您编码愉快!