直播

闭包(closure)

2018-09-17  本文已影响120人  小小的白菜

闭包是函数和声明该函数的词法环境的组合。MDN

MDN上的栗子
function makeFunc() {
    var name = "Mozilla";
    function displayName() {
        alert(name);
    }
    return displayName;
}

var myFunc = makeFunc();
myFunc();

为什么要使用闭包?

局部变量无法共享和长久的保存,而全局变量可能造成变量污染,所以我们希望有一种机制既可以长久的保存变量又不会造成全局污染。

怎么样使用闭包?

注意一:手动解除引用
function makeAdder(x) {
  return function(y) {
    return x + y;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2));  // 7
console.log(add10(2)); // 12

// 释放对闭包的引用
add5 = null;
add10 = null;

add5 和 add10 都是闭包。它们共享相同的函数定义,但是保存了不同的环境。在 add5 的环境中,x 为 5。而在 add10 中,x 则为 10。最后通过 null 释放了 add5 和 add10 对闭包的引用。

在javascript中,如果一个对象不再被引用,那么这个对象就会被垃圾回收机制回收;而makeAdder对象被全局变量add5和add10引用,就会占用内存空间。

注意二:闭包遇上for循环

闭包只能取得包含函数中任何变量的最后一个值,这是因为闭包所保存的是整个变量对象,而不是某个特殊的变量。

function test() {
  var arr = [];
  for(var i = 0;i < 10;i++) {
    arr[i] = function() {
      return i;
    };
  }
  for(var a = 0;a < 10;a++) {
    console.log(arr[a]());
  }
}
test();  // 连续打印10个10

讨论区链接

函数1作用域
for(var i = 0; i < 10; i++) { 函数1作用域
        我在函数1作用域中
        arr[i] = function() { 函数2作用域
          我在函数2作用域中
          return i;
        };
}
函数1作用域
console.log(i);

console.log(i); 执行到这里的时候,i 是10,既然这里是10,那么在函数2作用域中访问i也是10,因为函数2作用域中没有,向上去函数1作用域中找,同一作用域中同一变量名的变量值肯定是相同的(未修改的情况下)。

当你用 let 的时候,如下:

块1作用域
for(let i = 0; i < 10; i++) { 块2作用域
    我在块2作用域中
    console.log(i); // 毫无疑问,这里的i从0依次增加到10  
    arr[i] = function() { 块3作用域
      我在块3作用域中
      return i;
    };
}
块1作用域

当你换成 let 的时候,读取i的时候,在当前作用域块3中没有找到,向上一个作用域块2寻找,在块2作用域中发现i,于是拿到值。

闭包的缺点

function Animal() {
  
  // 私有变量
  var series = "哺乳动物";
  function run() {
    console.log("Run!!!");
  }
  
  // 特权方法
  this.getSeries = function() {
    return series;
  };
}

思考题

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

var a = fun(0);  // ?
a.fun(1);        // ?        
a.fun(2);        // ?
a.fun(3);        // ?

var b = fun(0).fun(1).fun(2).fun(3);  // ?

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

参考文章

https://zhuanlan.zhihu.com/p/27857268
https://juejin.im/entry/57d60f7067f3560057e37e25
http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html

上一篇下一篇

猜你喜欢

热点阅读