什么是闭包?有哪些使用场景?优缺点是什么?

本文详细解释了JavaScript中闭包的概念,包括其定义、工作原理和应用场景。闭包允许内部函数访问并操作外部函数作用域内的变量,实现变量的持久化存储。通过实例展示了闭包在计数器等实用功能中的运用,同时也提到了闭包可能带来的性能影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:什么是闭包?

闭包就是能够读取其他函数内部变量的函数,说白了闭包就是个函数,只不过是处于其他函数内部而已。

由于在javascript中,只有函数内部的子函数才能读取局部变量,所以说,闭包可以简单理解成“定义在一个函数内部的函数“。

所以,在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

知乎大神说:闭包是指在 JavaScript 中,内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。

二:用途是什么?

1.访问函数内部的变量

2.防止函数内部的变量执行完城后,被销毁,使其一直保存在内存中。

写一个关于闭包的例子:

function outer(x) {

// 参数相当于局部的变量

    function inner(y) {

       console.log(x + y);

}

   return inner;

}

var closure = outer(3);

closure(7); // 输出10

 

inner函数把自己内部的语句,和自己在声明时所处的作用域一起封装成了一个密闭的环境,我们就称之为闭包。

函数本身就是一个闭包,函数在定义的时候,就能记住自己的外部环境和内部语句,每次执行的时候,会参考定义时的密闭环境。

关于闭包的用处的例子:看的MDN网站上的例子,讲的非常清楚了

var makeCounter = function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }  
};

var Counter1 = makeCounter();
var Counter2 = makeCounter();
console.log(Counter1.value()); /* logs 0 */
Counter1.increment();
Counter1.increment();
console.log(Counter1.value()); /* logs 2 */
Counter1.decrement();
console.log(Counter1.value()); /* logs 1 */
console.log(Counter2.value()); /* logs 0 */

每次调用其中一个计数器时,通过改变这个变量的值,会改变这个闭包的词法环境。然而在一个闭包内对变量的修改,不会影响到另外一个闭包中的变量。以这种方式使用闭包,提供了许多与面向对象编程相关的好处 —— 特别是数据隐藏和封装

缺点:

如果不是某些特定任务需要使用闭包,在其它函数中创建函数是不明智的,因为闭包在处理速度和内存消耗方面对脚本性能具有负面影响。

实际项目应用:

封装一个公共弹框,点击确定取消按钮,会触发退订事件,调用退订接口,成功之后还会刷新列表。

弹框组件接受一个 确定按钮的事件,OK参数。

如果 OK 不写成箭头函数,那么里面的this 指向的是OK 而不是vue ,就无法执行,methods 的方法,也可以 在外部

let _this = this;

ok: function() {

_this.exitOrder();

}

这么写也可以。

 

05-30
<think>嗯,用户想了解闭包的概念以及它和装饰器的关系。之前我回答过关于装饰器的问题,现在需要结合之前的回答来补充闭包的内容。首先,我得明确闭包的定义,可能要从嵌套函数和变量作用域开始讲起。闭包在Python中是如何形成的?比如,外层函数返回内层函数,内层函数引用了外层函数的变量,这样就形成了闭包。这样闭包可以保存外层函数的状态,对吧?然后要说明闭包的作用,比如数据封装、延迟计算、保持状态等。可能需要举一个计数器的例子,这样用户能直观理解闭包如何保存状态。比如外层函数定义一个计数器变量,内层函数每次调用时增加这个计数器,并返回当前值。这样每次调用闭包函数时,计数器不会被重置。接下来要联系到装饰器。装饰器的本质其实就是一个返回函数的高阶函数,而很多装饰器内部使用闭包结构。比如之前用户提到的log_time装饰器,里面wrapper函数引用了外层函数log_time的参数func,这就是闭包的应用。通过闭包,装饰器能够记住被装饰的函数,并在调用时执行额外的逻辑。 还要注意闭包和装饰器的区别,闭包是概念,装饰器是应用。装饰器利用闭包来保持装饰函数的状态,比如被装饰的函数、装饰器的参数等。可能需要举一个带参数的装饰器的例子,说明外层函数接收参数,内层装饰器函数使用这些参数,形成闭包,从而在调用时保留这些参数的值。 另外,用户可能想知道闭包在装饰器中的具体应用场景,比如保持装饰器的配置或者多次调用间的状态。比如重试装饰器retry,里面需要记录尝试的次数,闭包可以让wrapper函数访问max_tries这个参数,而不需要全局变量。然后要回答用户的问题,闭包的作用和与装饰器的关联,需要分点说明,结构清晰。可能还需要提到闭包中的变量访问规则,比如nonlocal关键字的使用,防止在Python中因为赋值操作而将变量视为局部变量。最后生成相关问题,可能涉及闭包的变量修改、装饰器中的闭包使用注意事项、闭包与类的区别等。确保问题覆盖用户可能进一步探索的方向。在写作过程中,要使用中文,数学公式用正确的LaTeX格式,比如变量用$variable$,独立公式用$$...$$。引用之前回答中的例子时,加上引用标识,比如[^1]。同时检查是否有遗漏的点,比如闭包的内存管理问题,或者装饰器叠加时的闭包情况,但可能不需要深入,保持回答简洁明了。</think>### 闭包的概念与作用 **闭包(Closure)** 是函数与其相关引用环境(即外层作用域中的变量)的组合体。当一个嵌套函数引用了外层函数的变量,且外层函数返回内层函数时,就形成了闭包。其核心作用是**保持状态**和**实现数据封装**。 #### 闭包的关键特征 1. **嵌套函数结构**:内层函数定义在外层函数内 2. **变量引用**:内层函数引用外层函数的变量 3. **返回函数对象**:外层函数返回内层函数作为返回值 ```python def outer_func(x): def inner_func(y): return x + y # 引用外层函数的变量x return inner_func # 返回闭包 closure = outer_func(10) print(closure(5)) # 输出15(保留x=10的状态) ``` ### 闭包与装饰器的关系 装饰器的本质是通过闭包实现的**高阶函数**应用。装饰器函数接收被装饰函数作为参数,在闭包中实现功能扩展,最后返回新的函数对象[^1]。 #### 典型装饰器的闭包结构 ```python def decorator(func): # 外层函数接收参数 def wrapper(*args): # 闭包函数 print("前置操作") # 扩展功能 result = func(*args) # 调用原函数(闭包保留func引用) print("后置操作") return result return wrapper # 返回闭包 @decorator def my_func(n): return n * 2 ``` ### 闭包在编程中的核心作用 | 作用类型 | 说明 | 数学表达示例 | |----------------|--------------------------------------|-------------------------------| | 状态保持 | 保存外层函数变量的最终状态 | 计数器:$f(x) = x + \Delta$ | | 延迟计算 | 捕获变量值但不立即执行 | 惰性求值:$g(x) = \int f(x)dx$| | 配置封装 | 将参数与环境绑定 | 参数化函数:$h(a)(x) = a \cdot x$ | #### 示例:闭包实现计数器 ```python def counter(): count = 0 # 外层变量 def increment(): nonlocal count # 声明非局部变量 count += 1 return count return increment c = counter() print(c(), c(), c()) # 输出1,2,3(保持count状态) ``` ### 闭包与装饰器的交互原理 1. **参数传递**:装饰器参数通过外层函数捕获,形成闭包环境 2. **函数替换**:装饰后的函数实际调用的是闭包函数`wrapper` 3. **状态隔离**:每个被装饰函数都会创建独立的闭包环境 #### 带参数装饰器的闭包结构 ```python def retry(max_attempts): # 外层获取装饰器参数 def decorator(func): # 中间层接收被装饰函数 def wrapper(*args): # 闭包函数 for _ in range(max_attempts): try: return func(*args) except Exception: pass raise RuntimeError return wrapper return decorator @retry(max_attempts=3) # 创建闭包保存max_attempts=3 def fetch_data(): # 数据获取逻辑 ``` ### 闭包的特殊注意事项 1. **变量捕获时机**:闭包捕获的是变量的引用,而非当前值 ```python funcs = [] for i in range(3): def wrapper(): return i # 所有闭包最终都捕获i=2 funcs.append(wrapper) print([f() for f in funcs]) # 输出[2,2,2] ``` 2. **内存泄漏风险**:长期存在的闭包可能阻止垃圾回收 3. **nonlocal声明**:在Python中修改外层变量需要`nonlocal`关键字
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值