JavaScript简餐——闭包


前言

写本《JavaScript简餐》系列文章的目的是记录在阅读学习《JavaScript高级程序设计(第4版)》一书时出现的各个知识点。虽是对读书的笔记和总结,但是希望它轻量、简洁、犀利,不会引起阅读疲劳,可以在碎片化时间和闲暇之余轻巧地沐浴一下知识点。每篇文章只针对一个小部分进行讲解式的梳理,来达到个人复习总结和分享知识的目的。


一、闭包概念

闭包:指的是那些引用了另一个函数作用域中变量的函数。通常是在嵌套函数中实现的。例如:
function Person() {
  let age = 29;
  return function sayAge() {
    console.log(age);
  };
}
在这里,内部函数sayAge函数引用了外部函数Perosn的变量age,即应用了另一个函数作用域中的变量。所以,sayAge函数就是一个闭包。

二、闭包的副作用

一般函数在执行完毕后,局部活动对象会被销毁,内存中就只剩下全局作用域。(在这里要说明一下,函数执行上下文中会有一个包含其中变量的对象,这个对象中包含函数的arguments、函数局部变量以及函数中定义的对象,我们称这个对象为变量对象。而在函数执行时,这个变量对象就称为活动对象。)但是当你定义一个闭包后,由于闭包会保留外部函数的作用域,导致外部函数的活动对象不能在它执行完毕后销毁,此时闭包的作用域链中仍然有对外部函数活动对象的引用。来看一个例子:
function Person() {
  let age = 29;
  addAge = function () { // addAge没有用var、let或者const声明,所以相当于定义在全局的函数
    ++age;
  };
  return function sayAge() {
    console.log(age);
  };
}

let result = Person();

result(); // 29
addAge();
result(); // 30
在这里,我们先运行result()(要知道我们的这个result函数等于sayAge函数),得到了age的值29,之后我们借助addAge()将age的值加1,再次运行result()时我们发现age的值变成30了。这足以证明,Person函数的局部变量age一直存在于内存中,并没有在调用后被销毁。这就会导致垃圾回收程序无法回收这个变量,从而引发内存泄漏。


对此,我们可以通过调用result()后将其设置为null来解除对外部函数的引用来释放内存,如下:
function Person() {
  let age = 29;
  addAge = function () { // addAge没有用var、let或者const声明,所以相当于定义在全局的函数
    ++age;
  };
  return function sayAge() {
    console.log(age);
  };
}

let result = Person();

result(); // 29

result = null; // 解除对函数的引用,这样就可以释放内存
闭包会保留包含它们的函数的作用域,所以比其他函数更占用内存。过度使用闭包可能导致内存过度占用,因此建议仅在十分必要时使用。

三、闭包的用途

1.在函数外部读取函数的内部变量

众所周知,在函数外部时不可以调用函数内部定义的变量的。但是通过闭包我们可以访问到函数的内部变量。具体原理是在函数中将闭包作为返回值返回,之后在函数外部再次调用这个闭包即可。例如:
function Person() {
  let age = 29;
  return function sayAge() {
    console.log(age);
  };
}

let result = Person(); // 29
//当然也可以这样调用:
Person()();

2.利用外部函数变量缓存值

以防抖函数为例:

function debounce(fn, wait = 1000) {
  let timer;
  return function () {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      fn.apply(this, arguments);
    }, wait);
  };
}

这里利用闭包,让外部函数定义的timer一直存在于内存中不被销毁,当防抖函数再次执行时就可以直接从内存中读取timer来判断是否还存在,从而来进行防抖限制。


四、总结

以上就是今天要讲的内容,今天介绍了一下闭包的概念、闭包的副作用以及它的作用。下一篇,我们来讲一下ES6新增的尾调用优化。撒花~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值