说到闭包这个概念我觉得不得不谈JS。闭包虽然其他语言​也都支持,但都没有JS那样过度的依赖闭包。

什么是闭包?

一句话概括:简单的说**在当前 函数/方法 里再定义一个或多个 函数/方法 **即可认为是闭包。

是不是没看懂?没关系我们继续往下分析。

闭包的目的是为了什么?

那闭包和装饰器是什么关系?

这个问题问得好,闭包的另一个作用就是实现装饰器。为什么闭包能够实现装饰器?这与编程语言的GC机制有关。

一般而言变量分配的内存不再引用时就会被标记删除,具体是什么时候删除这是虚拟机实现的问题。什么时候不再引用呢?大部分情况下在下文中不再出现就会被标记

比如:

function f() {
  var x = 9;
  var y = x * x;
  f2(y); // 这时x已经不需要了
  // 当然这里还有常量优化的问题……
}

而下面代码中的

outer = function() {
  var i = 9;
  return function inner() {
    return i;
  }
}
outer // -> <function>
outer() // -> 9

在返回闭包inner函数后i还是被引用的,所以i的内存并不会被释放。但外部无法访问i变量,也就相当于是私有属性了。

哦,我好像懂了

确实讲到这里大部分也应该搞懂了,但我们还没有谈到装饰器的实现部分。所谓装饰器就是将回调包裹在闭包内然后返回闭包函数的做法。

function wrapper(callback) {
  var count = 0;
  return function() {
    console.log(++count);
    return callback.apply(this, arguments);
  }
}

f = wrapper(x => x*x);

f(1) // 1 1
f(2) // 2 4
f(9) // 3 81

// 顺便说一下:
// 1. js中的this指向的是当前调用他的对象
// 2. arrow function没有自己的this和arguments。

装饰器装饰过的 函数/方法 都有自己的独立闭包作用域。如果你再使用wrapper函数实现一个新的闭包,那么新的函数与之前的另一个闭包函数之间是互不干扰的

其实互不干扰很容易理解。因为每当你调用函数时分配的内存都是唯一的,返回后的装饰器引用的也是唯一的内存,所以不存在干扰的问题。

小结

额外知识点

wrapper装饰器被返回以后绑定在某个对象上后this始终指向调用它的对象。如下:

o = { i: 9, j: 8, k: 7 }
o.show = wrapper(function() {
  console.log(JSON.stringify(this));
});

o.show(); // 1 {"i":9,"j":8,"k":7}
o.show(); // 2 {"i":9,"j":8,"k":7}
o.m = function() {
  function f() {
    console.log(this);
  }
  f(); // f中this指向window,因为它未绑定
  // 在nodejs中this未绑定指向global作用域
}

(另外祝自己18岁生日快乐😝)