词法作用域指变量可访问性由源码中声明位置决定,而非调用时的执行上下文;JS在解析阶段即确定函数能访问的变量,与调用方式无关。

JavaScript 的作用域不是靠“声明位置”直观看出来的,而是由函数定义时的词法环境决定的——也就是说,function 创建的作用域在写代码时就固定了,和怎么调用无关。
什么是词法作用域(Lexical Scope)
词法作用域指变量的可访问性取决于它在源码中声明的位置,而不是运行时的调用栈。JS 引擎在解析阶段就确定了每个 function 能访问哪些变量。
常见误解:以为 var 声明在 if 或 for 里会生成局部作用域——不会。if 和 for 没有块级作用域(ES5 及以前),只有 function、eval 和 ES6 的 let/const 块才创建新作用域。
-
var声明会被提升到其所在函数(或全局)顶部,且不绑定块 -
let和const有块级作用域,但不会被提升(存在暂时性死区 TDZ) -
function声明也会被提升,且创建独立词法环境
全局作用域 vs 函数作用域的实际表现
全局作用域是所有未被任何 function 包裹的变量所在的地方;函数作用域则是每次调用 function 时创建的私有环境,内部可访问自身声明 + 外层作用域变量(闭包基础)。
立即学习“Java免费学习笔记(深入)”;
容易踩的坑:
- 在全局作用域用
var声明,会自动挂到window(浏览器)或global(Node.js)上;用let/const则不会 - 嵌套函数内修改外层
var变量,会影响外层;但若用let声明同名变量,则是遮蔽(shadowing),互不影响 -
this不属于作用域链,它的值由调用方式决定,和词法作用域无关
示例:
function outer() {
var a = 1;
let b = 2;
function inner() {
console.log(a); // 1,可访问外层 var
console.log(b); // 2,可访问外层 let
}
inner();
}
ES6 的块级作用域(let/const)如何改变行为
if、for、switch 等语句块现在能形成独立作用域,但仅对 let 和 const 有效,var 仍泄漏到函数或全局。
典型问题场景:
-
for (var i = 0; i console.log(i), 0)输出三个3(因为只有一个i,循环结束时值为3) - 改成
let i,每次迭代都绑定新绑定,输出0、1、2 -
const声明不可重新赋值,但对象属性仍可修改(绑定不可变,值可变)
为什么 eval 和 with 是例外
eval 在非严格模式下可动态创建变量,影响当前作用域;严格模式下它有自己独立作用域。而 with 会把传入对象临时注入作用域链顶端,导致变量查找顺序混乱、性能差、严格模式下直接禁用。
所以:永远不要用 with;避免在生产环境用 eval;现代打包工具(如 Webpack)遇到 eval 通常会跳过优化。
真正需要动态执行代码时,优先考虑 Function 构造函数(它只访问全局作用域,更可控)。











