JavaScript作用域是词法作用域,由代码结构在运行前确定,分全局、函数、块级(ES6起);var提升至函数顶,let/const有TDZ;闭包捕获变量绑定而非值;this与作用域无关,取决于调用方式。

作用域决定变量能否被访问到
JavaScript 作用域不是“变量在哪定义”,而是“当前执行位置能合法读写哪些变量”。它在代码运行前就由词法结构确定(即词法作用域),和函数调用栈无关。这意味着 eval 或 with 会破坏静态可预测性,应避免使用。
全局、函数、块级作用域的边界在哪
ES5 只有全局和函数作用域;ES6 引入 let 和 const 后,{} 块(如 if、for、独立块)也形成作用域。但注意:
-
var声明仍仅受函数边界限制,会变量提升(hoisting)到函数顶部 -
let/const不提升,且在声明前访问会抛出ReferenceError(暂时性死区 TDZ) -
function声明会被提升并初始化,function expression则按var规则处理(仅声明提升)
function foo() {
console.log(a); // undefined(var 提升但未赋值)
console.log(b); // ReferenceError(TDZ)
var a = 1;
let b = 2;
}
闭包是如何捕获外部作用域的
当一个函数引用了其外部作用域中的变量,并被返回或传递到其他作用域执行时,就形成了闭包。关键点是:它捕获的是变量的「绑定」,而非值的快照。
- 多个闭包共享同一外部变量(比如循环中创建的函数)
-
let在每次循环迭代中创建新绑定,因此常用来避免经典循环问题 - 闭包会阻止外部作用域被垃圾回收,过度使用可能引发内存泄漏
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0); // 输出 3, 3, 3
}
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j), 0); // 输出 0, 1, 2
}
this 和作用域不是一回事
新手常混淆 this 绑定和作用域链查找。作用域解决的是「标识符在哪里找」(如 x 是全局变量还是参数),而 this 是运行时基于调用方式动态确定的上下文对象。箭头函数不绑定 this,但它依然遵循词法作用域规则去查找外层变量。
立即学习“Java免费学习笔记(深入)”;
-
function内部的this与作用域无关,取决于调用位置(如obj.method()中this === obj) - 箭头函数的
this是词法继承的,但它的arguments、super等也一样不绑定 - 用
debugger断点查看Scope面板,比猜this更可靠
.js 文件)不是全局作用域,而是模块作用域;import 的绑定是实时只读引用,不是拷贝;而 eval('var x = 1') 在非严格模式下会泄漏到全局,严格模式下则报错——这些边界情况,在重构旧代码或调试跨模块变量时经常出人意料。










