发现宝藏
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【宝藏入口】。
闭包(Closure)是编程中一个非常重要的概念,主要存在于 JavaScript 和其他支持函数式编程的语言中。理解闭包对于写出高效、模块化的代码至关重要。
什么是闭包?
闭包是指:一个函数能够访问其外部函数作用域中的变量,即使外部函数已经执行完毕。
从本质上看,闭包是函数与其外部环境的引用的结合。当一个内部函数被返回或赋值给外部变量时,它依然“记住”了定义时所处的外部作用域,从而形成闭包。
闭包的实现原理
闭包的本质是作用域链。当一个函数被创建时,它会保存对其所在执行上下文(作用域)的引用。即使外部函数执行结束,闭包中的变量依然存在于内存中,因为被闭包引用着。
闭包的代码示例
1. 基本示例
function outerFunction() {let count = 0; // 外部函数中的变量function innerFunction() {count++; // 内部函数可以访问外部变量console.log(count);}return innerFunction; // 返回内部函数
}const myClosure = outerFunction();
myClosure(); // 输出:1
myClosure(); // 输出:2
myClosure(); // 输出:3
解释:
outerFunction
返回了innerFunction
。- 当
outerFunction
执行完毕后,它的局部变量count
按理说应该被销毁。 - 但是,因为返回的
innerFunction
依然引用了count
,所以count
依然保存在内存中,形成了闭包。
2. 实现私有变量
闭包常用来创建私有变量,避免全局污染。
function createCounter() {let count = 0; // 私有变量return {increment: function () {count++;return count;},decrement: function () {count--;return count;},getCount: function () {return count;}};
}const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.getCount()); // 2
console.log(counter.decrement()); // 1
解释:
count
是createCounter
内部的变量,外部无法直接访问。increment
、decrement
和getCount
方法通过闭包机制访问了count
,但外部代码无法修改count
。
闭包的实际应用场景
1. 数据封装(私有变量)
如上所示,闭包可以用来封装变量,防止外部直接访问。
2. 延迟执行与回调
闭包使得变量在异步操作中保持正确的值。
for (var i = 1; i <= 3; i++) {setTimeout(function () {console.log(i);}, 1000);
}
// 输出:4, 4, 4 (因为 i 是 var 声明的全局变量)// 使用闭包修正
for (let i = 1; i <= 3; i++) {setTimeout(function () {console.log(i);}, 1000);
}
// 输出:1, 2, 3
3. 函数柯里化
闭包可以实现柯里化,将一个函数拆分成多个函数调用。
function add(x) {return function (y) {return x + y;};
}const add5 = add(5);
console.log(add5(3)); // 输出:8
console.log(add5(10)); // 输出:15
4. 缓存与记忆化
闭包可以保存函数执行结果,提高性能。
function memoizedAdd() {let cache = {};return function (x) {if (cache[x] !== undefined) {console.log('From cache');return cache[x];} else {console.log('Calculating result');cache[x] = x + 10;return cache[x];}};
}const addWithMemo = memoizedAdd();
console.log(addWithMemo(5)); // Calculating result -> 15
console.log(addWithMemo(5)); // From cache -> 15
闭包的注意事项
-
内存占用问题:
- 闭包会导致外部函数的变量无法被垃圾回收器回收,容易造成内存泄漏。
- 解决方法:不再需要时将引用置为
null
。
let myClosure = outerFunction(); myClosure = null; // 释放闭包引用,释放内存
-
性能问题:
- 频繁创建闭包可能会影响性能。
- 需要合理使用闭包,避免过度嵌套。