JS闭包和作用域

154 阅读3分钟

JS闭包和作用域

执行环境定义了变量或者函数有权限访问的其他数据,决定了他们各自的行为。

  • 每个函数都有自己的执行环境。当执行到一个函数时,函数的环境就会被推入到一个环境栈中,在函数执行完后,栈将其弹出, 将控制权返回给之前的执行环境
  • 当代码在一个函数中执行时,会创建变量对象的一个作用域链,作用域链的作用:保证对执行环境有权访问的所有变量和函数的 有序访问。

作用域链,当执行一个函数的时候,变量的访问顺序是,现在当前的作用域上查找,没找到的话,就往上层作用域找,一直找到 window为止。作用域是在定义的时候就确定了。

  (function wrap () {
    var num = 10;
    var getNum = function() {
      console.log(num);
    }
    var fun1 = function () {
      console.log(num)
      var num = 20;
      getNum();
      console.log(num);
    }
    fun1();
  })();
如上代码,打印结果分别为undefined、10、20,第一个num为undefined是因为,在fun1函数中,它会现在当前作用域(fun1)中查找num变量,在当前作用域中,有一个num变量,所以不会再往上继续查找num变量了,变量num此时还没有赋值,所以是undefined。 第二个是10,是因为在getNum函数中,在当前作用域(getNum)中查找num变量,没找到就接着往上层作用域(wrap)中查找,找到num的值为10。 第三个是20,在fun1的作用域中,num的值为20,所以是20

垃圾收集

javaScript具有自动垃圾收集机制。原理:间隔固定的时间,找出不用的变量后释放其占用的内存。 垃圾回收机制方法有标记清除和引用计数

闭包:是指有权访问另一个函数作用域中变量的函数。

闭包的特点:

  • 函数嵌套函数。
  • 函数内部可以引用外部的参数和变量。
  • 参数和变量不会被垃圾回收机制回收 闭包的优缺点:
    • 优点:避免全局变量的污染、函数封装
    • 缺点:常驻内存,增加内存使用量。使用不当会很容易造成内存泄露。
  var fun1 = function() {
    var num = 1;
    return function() {
      num++;
      console.log(num, this);
    }
  }
  var fun2 = fun1();
  console.log(fun2()) // 2, window
  console.log(fun2()) // 3, window

通常,函数的作用域及其所有变量都会在函数执行结束后被销毁,但是由于闭包的存在,这个函数的作用域就会一直保存到闭包不存在为止。

  function fun(n,o){
    console.log(o);
    return {
      fun: function(m){
        return fun(m,n);
      }
    };
  }

  var a = fun(0);  //    n=0, o=undefined  结果undefined
  a.fun(1);        //    m=1, n=0, 执行fun(1,0),n=1,o=0,结果0    
  a.fun(2);        //    m=2, n=0, 执行fun(2,0),n=2,o=0,结果0
  a.fun(3);        //    m=3, n=0, 执行fun(3,0),n=3,o=0,结果0

  var b = fun(0).fun(1).fun(2).fun(3); 
  /** 
  n=0, o=undefined  结果undefined、
  m=1, n=0, 执行fun(1,0),n=1,o=0,结果0、
  m=2, n=1, 执行fun(2,1),n=2,o=1,结果1、
  m=3, n=2, 执行fun(3,2),n=3,o=2,结果2,
  最终打印undefined、0、1、2
  **/

  var c = fun(0).fun(1);  // undefined、0
  c.fun(2);        //  1
  c.fun(3);        //  1