函数与作用域
约 1095 字大约 4 分钟
2025-11-24
什么是闭包
问题
什么是闭包?
闭包有什么用途?
闭包是指一个函数能够记住并访问它的词法作用域,即使这个函数在其词法作用域之外被调用。 它发生在当一个函数嵌套在另一个函数内部时,内部函数可以访问外部函数的变量和参数,即使外部函数已经执行完毕并返回。
简单来说,闭包就是“函数 + 函数声明时的词法作用域”组合形成的一个整体。
闭包的特性
- 内部函数可以访问外部函数的变量。
- 外部函数执行完成后,其作用域不会立即销毁,而是被闭包保留。
- 闭包可以让变量的生命周期延长,直到不再有任何引用为止。
闭包的作用
- 数据封装与信息隐藏:通过闭包可以创建私有变量,避免全局污染。
- 回调函数和事件处理:在异步编程中,闭包常用于保存状态。
- 工厂函数:通过闭包返回特定功能的对象。
示例代码
function outerFunction() {
let outerVariable = "I'm outside!";
function innerFunction() {
console.log(outerVariable); // 访问外部函数的变量
}
return innerFunction;
}
const closure = outerFunction();
closure(); // 输出: I'm outside!在这个例子中,innerFunction 是一个闭包,它记住了 outerFunction 的作用域,并能够在 outerFunction 执行完毕后继续访问 outerVariable。
闭包的注意事项
- 内存泄漏:由于闭包会持有对外部作用域的引用,如果未正确释放,可能导致内存占用过高。
- 性能问题:过多使用闭包可能会影响程序性能,尤其是在循环或大量嵌套的情况下。
作用域(Scope)
问题
什么是作用域?
什么是作用域链?
作用域是变量、函数或对象的可访问范围,决定了代码中哪些部分可以访问这些标识符。JavaScript 中有以下作用域类型:
1. 全局作用域
- 定义在函数或代码块外的变量
- 可在代码任何位置访问
let globalVar = "全局变量"; // 全局作用域 function show() { console.log(globalVar); // 可以访问 }
2. 函数作用域
- 通过
var在函数内定义的变量 - 只能在函数内部访问
function func() { var localVar = "局部变量"; // 函数作用域 console.log(localVar); // 可以访问 } console.log(localVar); // 报错:localVar未定义
3. 块级作用域(ES6+)
- 通过
let/const在代码块({})内定义的变量 - 只能在代码块内访问
if (true) { let blockVar = "块级变量"; // 块级作用域 console.log(blockVar); // 可以访问 } console.log(blockVar); // 报错:blockVar未定义
作用域链(Scope Chain)
作用域链是 JavaScript 查找变量的机制。当访问一个变量时,会按照以下顺序逐层向上查找:
- 当前作用域 → 2. 外层函数作用域 → 3. 全局作用域
作用域链示例
let globalVar = "全局"; // 全局作用域
function outer() {
let outerVar = "外层"; // outer函数作用域
function inner() {
let innerVar = "内层"; // inner函数作用域
console.log(innerVar); // 内层(当前作用域)
console.log(outerVar); // 外层(外层函数作用域)
console.log(globalVar); // 全局(全局作用域)
}
inner();
}
outer();关键区别与特性
| 特性 | 作用域(Scope) | 作用域链(Scope Chain) |
|---|---|---|
| 本质 | 变量的可访问范围 | 变量查找的层级链路 |
| 核心作用 | 隔离变量,避免命名冲突 | 确定变量从哪里被访问 |
| 典型应用 | 全局变量 vs 局部变量 | 闭包、嵌套函数访问外层变量 |
| ES6 影响 | 新增块级作用域(let/const) | 作用域链结构更清晰,避免变量提升问题 |
实际应用场景
闭包:通过作用域链保留对外部变量的引用
function createCounter() { let count = 0; // 被闭包保留的作用域变量 return function() { return ++count; }; } const counter = createCounter(); console.log(counter()); // 1避免污染全局作用域
(function() { var privateVar = "私有变量"; // 限制在IIFE作用域内 })();
总结
- 作用域是规则,决定“变量在哪里可用”
- 作用域链是路径,决定“变量从哪里找到”
- 合理利用作用域能提升代码健壮性,而理解作用域链是掌握闭包等高级特性的基础。