js let var const 容易混淆的点 变量提升 和 作用域

91 阅读3分钟

一,先搞明白易混淆的点: undefined 与 undeclared(未声明) 的区别

  • 已在作用域中声明但还没有赋值的变量,是 undefined 的。相反,还没有在作用域中声明过的变量,是 undeclared 的。

  • 顺序是:声明----> 自动初始化为undefined---> 赋值为真正值

  • 对于未声明变量的引用,浏览器会报引用错误,如 ReferenceError: b is not defined

二,确定三个常见作用域的定义:

  • 要注意的是 var 是不受块级作用域{}的管束的!!!
  • var、 let、 const 在作用域外访问时候,报错:ReferenceError: b is not defined,-----表示函数未声明。

1. 全局作用域

  • 函数外部声明的变量或函数,属于全局作用域
  • 整个程序都可以访问这些变量和函数。
var a = 10;  // 全局变量
function foo() {
  console.log(a); // ✅ 10,全局变量可以在函数内访问
}
foo();
console.log(a); // ✅ 10,全局变量可以在任何地方访问

2. 函数作用域

  • var 声明的变量 只在当前函数内部可见,不能在函数外部访问。
  • 这是 JavaScript 早期的作用域机制。

示例:

function foo() {
  var b = 20;  // 变量 b 仅在 foo() 内部可见
  console.log(b); // ✅ 20
}
foo();
console.log(b); // ❌ ReferenceError: b is not defined(b 只存在于函数作用域)

3. 块级作用域(letconst

  • ES6 引入 letconst,它们具有块级作用域,即它们的作用范围仅限于 {} 代码块内部
  • 块级作用域的好处:避免变量污染全局作用域,提升代码可维护性。

示例:

{
  let x = 30;
  const y = 40;
  console.log(x, y); // ✅ 30, 40
}
console.log(x, y); // ❌ ReferenceError: x is not defined

三, var 和let const 都能变量提升, 但有区别

  • var 声明的变量被提升,并初始化为 undefined

  • let 声明的变量也被提升,但不会初始化,因此访问时会报 ReferenceError

Var

函数作用域
function testVar() {
    console.log(a); // undefined(变量提升初始化为undefined,但未赋值)
    var a = 10;
    console.log(a); // 10
}
testVar();
块作用域
{
    console.log(b); // undefined(变量提升,但未赋值)
    var b = 20;
    console.log(b); // 20
}
console.log(b); // 20(`var` 没有块级作用域,相当于全局变量)

解析
var b 虽然在 {} 内部声明,但因为 var 只有函数作用域,没有块级作用域,所以 b 实际上是在外部作用域中定义的。

全局作用域
console.log(c); // undefined(变量提升,但未赋值)
var c = 30;
console.log(c); // 30

解析
var c 在全局作用域中声明,变量 c 被提升到全局作用域的顶部,并初始化为 undefined

let, const

let 声明的变量也会被提升,但不会初始化,访问时会报 ReferenceError

函数作用域
function testLet() {
    console.log(d); // ReferenceError: Cannot access 'd' before initialization
    let d = 40;
    console.log(d); // 40
}
testLet();

解析
let d 被提升到作用域顶部,但不会初始化,访问 d 时会报 ReferenceError

分析:变量提升了,也就它现在被声明了,但是没初始化, 在执行语句(let d)之前,是放在暂时性死区的,也就是访问了就报错的Cannot access 'd' before initialization, 但是因为已经声明了,所以不会报: d is not defined

块作用域
{
    console.log(e); // ReferenceError: Cannot access 'e' before initialization
    let e = 50;
    console.log(e); // 50
}
console.log(e); // ReferenceError: e is not defined(`let` 具有块级作用域)

解析
let e 只在 {} 作用域内有效,出了块作用域 e 就不存在了。

全局作用域
console.log(f); // ReferenceError: Cannot access 'f' before initialization
let f = 60;
console.log(f); // 60

解析
let f 在全局作用域中声明,但不会被初始化,访问 f 会报错。和 var 不同,let 不会自动成为 window 对象的属性。