闭包的理解

这次是基于作用域链对闭包的新理解以及对闭包做一个全面完整的理解.

闭包的理解

js作用域链

  • JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里.
  • 嵌套的函数可以访问到其外层作用域中声明的变量。
  • 如果函数找不到自己的作用域中找不到需要的变量或者方法的话,那么它就会往上去找和自己在同一条作用域上的函数,一直往上找,直到window。
  • js中函数的作用域链中,处于尾端的函数可以一直往上找自己需要的变量或者方法,直到window。
  • 任何一条作用域链的顶部都是window,因为js中所有的变量或者方法都是Window这个对象的属性或者方法。

从作用域来理解闭包

  • 闭包的基本结构是函数嵌套函数.
  • 那么内部的函数和外部的函数就处于同一条作用域上,所以内部的函数可以使用外部函数的属性和方法。
  • 因为内部的函数是被return出去的,所以在这条作用域之外的环境也可以在使用外部函数的方法或者属性了,那么这个外部函数就是一个闭包.
  • 这样就相当于把闭包的私有变量或者方法拿来当做全局变量来使用了。这样做的好处是避免全局变量的污染。
  • 但是也有缺点,就是闭包的方法和属性不会被js的垃圾机制回收,使用不当会造成内存泄露。

闭包的三个特性

  1. 函数嵌套函数;
  2. 可以在全局环境中使用闭包的私有变量和方法;
  3. 闭包的私有变量和方法不会被js的垃圾机制回收.

闭包的作用

给同一个对象的同一个属性可以绑定不同的事件

  • 每创建一个新的闭包实例,都会开辟一个新的内存空间,所以闭包实例之间是互不影响的。
  • 利用这个特性可以给同一个事件源绑定不同的属性。

创建命名空间

命名空间的优点

  1. 所有变量都是命名空间的私有变量,需要使用哪个暴露哪个即可,非常方便。
  2. 避免了全局变量的污染。
  3. 可维护性高,可扩展性高。
  4. 且扩展方法的话,对原来的代码没有影响。

开闭原则

  1. 开:对扩展开发,即可以在原有的命名空间上扩展新的方法。
  2. 闭:对修改封闭,即要扩展的话不能在原有的代码上扩展。

####利用匿名函数创建命名空间

  • 因为js中只有函数作用域和全局作用域,而没有块级作用域。所以我们可以创建函数作用域来代替块级作用域的作用.
  • 命名空间体现了模块化,组件化,面向对象编程的思想。
  • 使用匿名函数的方法是创建即可以立即调用,省去了创建函数实例的步骤。要使用的时候直接通过命名孔家.方法名或者属性名即可以调用.
  • 命名空间的格式是:在匿名函数内创建多个方法或者属性。然后return一个对象.需要暴露出去的方法或者属性直接return出去就可以了.

      var yan7 = (function() {
          var num = 100;
    
          function add() {
              return num += 10;
          }
    
          return {
              sub: function() {
                  return num -= 10;
              },
              mul: function() {
                  return num *= 10;
              },
              div: function() {
                  return num /= 10;
              }
          }
      })();
    
  • 根据开闭原则,要给命名空间添加方法不需要改变源代码,只需要另写一块代码就可以了:

      var yan7 = (function(obj) {
          yan7.mod = function () {
              return num %= 10;
          }
          return yan7;
      })(window.yan7 || {});
    

总结

  • 闭包是函数作用域的体现,
  • 闭包的作用是私有化变量,将闭包的私有变量暴露出去供全局使用,这样的好处的私有化变量,避免了代码污染;
  • 特点是函数嵌套函数,并且把内部的函数return出去,通常内部的函数会使用外部函数的方法或者变量。