闭包是能访问到外部函数作用域中变量的函数

闭包代码示例👇:
- function outer() {
- let num = 10
- //内部函数要作为返回值返回
- function init() {
- num++ //内部函数引用外部函数outer中的num变量
- console.log('num', num);
- }
- return init
- }
- let result = outer() // 调用 outer 函数,返回一个闭包
- result() // 输出 11
- result() // 输出 12
变量的可见性是由它在代码中被声明的位置决定的,即在函数创建时就已经确定了,和调用无关,闭包利用的就是词法作用域
闭包的生命周期是在其创建时开始,并在不再被引用时结束。
闭包的生命周期取决于是否还有对闭包的引用。只要闭包仍然被其他代码、变量或函数引用,它就会一直存在。当没有任何引用指向闭包时,垃圾回收机制将自动回收闭包所占用的内存空间。
如下代码示例,将result设置为null,便解除对闭包的引用
- function outer() {
- let num = 10
- //内部函数要作为返回值返回
- function init() {
- num++ //内部函数引用外部函数outer中的num变量
- console.log('num', num);
- }
- return init
- }
- let result = outer() // 调用 outer 函数,返回一个闭包
- result() // 输出 11,每调用一次num+1
-
- // 此时,闭包仍然被变量 result 引用,因此它的生命周期还未结束
-
- result = null; // ⭐⭐解除对闭包的引用
场景1:封装私有变量
场景2:延迟执行
场景3:模块化
场景4:缓存数据
闭包可以创建私有变量,外部无法直接访问或修改,从而保护变量不受外部的干扰。
- function createCounter() {
- let count = 0
- function add() {
- count++
- console.log(count);
- }
- return add
- }
- const counter = createCounter()
- counter() //打印 1
- counter() //打印 2
- counter() //打印 3
闭包可以在异步操作中用于保存状态或数据,并在需要时执行回调函数。
- function delays(delay) {
- return function () {
- setTimeout(() => {
- console.log(`延迟${delay}`);
- }, delay)
- }
- }
- const delayFunction = delays(2000)
- delayFunction()
利用闭包可以创建模块化的代码结构,将相关的函数和数据封装在一个闭包内部,通过返回的公共接口来访问和操作这些内部成员。这种方式可以避免全局命名空间的污染,提高代码的可维护性和重用性。
- const myModule = (function () {
- let count = 0
- function add(num) {
- count += num
- }
- function dec(num) {
- count -= num
- }
- function getCount() {
- return count
- }
- return { add, dec, getCount }
- })();
- myModule.add(2)
- myModule.dec(1)
- console.log(myModule.getCount()); //输出1
使用闭包可以在函数执行完成后,仍然保持对其词法环境中变量的访问权限。这样可以实现缓存值,避免重复计算或重复访问外部数据。在这个例子中,getName 函数记住了 age 的值,可以在后续调用中使用同一个值而不需要重新计算或获取。
- function bar() {
- let name = 'pig'
- let age = 1
- let innerBar = {
- getName() {
- console.log(age);
- return name
- },
- setName(newName) {
- name = newName
- }
- }
- return innerBar
- }
- const foo = bar()
- console.log(foo.getName()); // 输出 1 pig
- foo.setName('dog')
- console.log(foo.getName()); // 输出 1 dog
使用闭包时,变量会一直存在于内存中,可能造成内存占用过高。如果闭包被滥用,可能导致内存泄漏问题。
由于闭包需要记住引用环境,所以在内存中的查找会比较耗时,可能会影响函数的执行效率。