闭包是属于比较高级的 js 变成范畴,最近在重新学习 JS 基础知识,尝试解释一下闭包。

概念

闭包函数:声明在一个函数中的函数,叫做闭包函数。
像这样:

  1. function parentFn(){
  2. return sonFn(){
  3. console.log(111)
  4. }
  5. }
  6. parentFn()() // 111

一个知识点:只有使用 () 函数才会执行。

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

这里所谓的寿命终结是指,当函数执行完成以后将会被内存回收机制收回。这里收回的也是函数在执行时开辟的私有作用域。

像这样:

  1. function parentFn(){
  2. var num = 1;
  3. return sonFn(){
  4. return num
  5. }
  6. }

为什么会产生闭包

JS 本身为了避免解释器过量消耗内存,造成系统崩溃, 自带有一套垃圾回收机制,垃圾回收机制能够检测到一个 对象是不是无用 的。检测到之后,就会把它占用的内存释放掉。但是实际工作中,我们也会需要一些变量不那么及时的被清理,所以就出现了闭包,用来达成这个效果。

另外,声明一个函数在全局形成了一个私有的作用域,所以我们有时候需要操作函数内(作用域)的变量就需要通过闭包来实现访问和修改的功能。

注意看重点,对象是不是无用的,那么怎样就无用呢??上面有一部分解释,函数执行完以后即被回收,我们来看下面的例子。

  1. var add = (function{
  2. var num = 1;
  3. return sonFn(){
  4. return num ++
  5. }
  6. })()
  7. add() // 1
  8. add() // 2

解释一下,自执行匿名函数被执行了,所以要销毁,但是它内部的一个变 numsonFn 所使用,sonFn 还没有执行,所以导致 num 不会被释放,我们知道函数对象和普通对象的区别就是不能缓存变量,这个例子因为内部引用所以不会被回收,所以导致这个 num 一直存在。

闭包能干什么

一直信奉一点,技术是为了解决问题而存在的,所以用技术来解决实际的问题,的才是技术存在的意义。

1. 作为私有空间,防止变量污染,有助于模块化代码

  1. var foo = (function(){
  2. var secret = 'secret';// “闭包”内的函数可以访问 secret 变量,而 secret 变量对于外部却是隐藏的
  3. return{
  4. get_secret: function(){ // 通过定义的接口来访问 secret
  5. return secret;
  6. },
  7. new_secret: function(new_secret){ // 通过定义的接口来修改 secret
  8. secret = new_secret;
  9. }
  10. };
  11. }());
  12. foo.get_secret(); // 得到 'secret'
  13. foo.secret; // Type error,不能访问
  14. foo.new_secret('a new secret'); // 通过函数接口,我们访问并修改了 secret 变量
  15. foo.get_secret(); // 得到 'a new secret'

2. 缓存变量值

  1. function add() {
  2. var counter = 0;
  3. return counter += 1;
  4. }
  5. add();
  6. add();
  7. add();
  8. // 计数器每次都是 1,函数执行一次既销毁。
  9. // 使用闭包
  10. function add() {
  11. var counter = 0;
  12. return function(){
  13. return counter += 1;
  14. }
  15. }
  16. var sum = add()
  17. sum() // 1
  18. sum() // 2
  19. sum() // 3
  20. // 补充,sum是一个非纯函数