一,先搞明白易混淆的点: 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. 块级作用域(let 和 const)
- ES6 引入
let和const,它们具有块级作用域,即它们的作用范围仅限于{}代码块内部。 - 块级作用域的好处:避免变量污染全局作用域,提升代码可维护性。
示例:
{
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 对象的属性。