javascript 中的词法作用域(lexical scope)是在代码编写阶段,由开发者在源代码中书写的位置决定的,而非程序运行时动态确定的。具体来说,一个变量的作用域范围取决于它在源码中被声明时所处的位置:如果变量在一个函数内部声明,它就属于该函数的局部作用域;如果在全局层级声明,则属于全局作用域。这种“静态”的绑定关系意味着,当代码执行时,引擎会沿着当前作用域向外层作用域逐层查找变量,直到找到为止或到达全局作用域。

嵌套函数如何访问外层变量
嵌套函数可以直接访问其外层函数(父级作用域)中声明的变量,这是词法作用域最核心的体现。这种现象通常被称为闭包的基础。无论嵌套函数在哪里被调用,它都能访问到定义它时的外层环境中的变量,而不是调用它时的环境。

function outer() {
let secret = 'I am outside';
function inner() {
console.log(secret); // 可以访问 outer 中的 secret
}
return inner;
}
const myFunc = outer();
myFunc(); // 输出: I am outside
在上述代码中,`inner` 函数在 `outer` 函数内部定义。当 `outer` 执行并返回 `inner` 函数引用后,即使 `outer` 的执行上下文已经销毁,`inner` 仍然保留了对 `secret` 变量的引用。这是因为词法作用域在编译阶段就已经确定了 `inner` 对 `secret` 的访问权限,这种机制允许数据私有化和状态保持。
立即学习“Java免费学习笔记(深入)”;
块级作用域与函数作用域的区别
ES6 引入的 `let` 和 `const` 引入了块级作用域(Block Scope),这与传统的函数作用域(Function Scope)有显著区别。使用 `var` 声明的变量只受函数作用域限制,而使用 `let` 或 `const` 声明的变量受包含它的代码块(如 `if`、`for` 或 `{}`)限制。这意味着在块级作用域中声明的变量,在块外部是不可见的。

if (true) {
var a = 1;
let b = 2;
const c = 3;
}
console.log(a); // 1, var 不受块级限制
console.log(b); // ReferenceError, let 仅限块内
console.log(c); // ReferenceError, const 仅限块内
这段代码展示了三种声明方式在块级作用域下的不同行为。`var` 声明的变量 `a` 泄漏到了全局作用域,因此可以在 `if` 块外部访问。而 `b` 和 `c` 严格限制在 `if` 块的 `{}` 内部,一旦离开该块,它们就不可访问。这种设计使得块级作用域更适合用于循环计数器或临时变量,避免了变量污染全局命名空间的问题。
立即执行函数表达式如何创建独立作用域
在 ES6 之前,为了模拟块级作用域或避免全局变量污染,开发者常使用立即执行函数表达式(IIFE)。IIFE 通过创建一个独立的函数作用域,将代码包裹在其中,从而确保内部声明的变量不会泄露到外部。这是一种利用函数作用域特性来隔离代码的有效手段。
(function() {
var privateVar = 'I am private';
console.log(privateVar); // 正常输出
})();
console.log(privateVar); // ReferenceError, 外部无法访问
IIFE 的核心在于函数定义后立即执行,且由于函数作用域的存在,`privateVar` 仅在 IIFE 内部可见。这种方式在现代 JavaScript 开发中虽然不如 `let/const` 常用,但在处理模块模式或兼容旧版浏览器时仍然具有实用价值。它清晰地展示了词法作用域如何通过函数边界来保护内部状态不被外部干扰。


















