A.2 处理闭包之间的交互

当存在多个内部函数时,很可能会出现意料之外的闭包。假设我们又定义了一个递增函数,这个函数中的增量为2:

代码清单A-9

  1. function outerFn() {
  2. var outerVar = 0;
  3. function innerFn1() {
  4. outerVar++;
  5. console.log('(1) outerVar = ' + outerVar);
  6. }
  7. function innerFn2() {
  8. outerVar += 2;
  9. console.log('(2) outerVar = ' + outerVar);
  10. }
  11. return {'fn1': innerFn1, 'fn2': innerFn2};
  12. }
  13. var fnRef = outerFn();
  14. fnRef.fn1();
  15. fnRef.fn2();
  16. fnRef.fn1();
  17. var fnRef2 = outerFn();
  18. fnRef2.fn1();
  19. fnRef2.fn2();
  20. fnRef2.fn1();

这里,我们通过对象返回两个内部函数的引用(这也示范了内部函数的引用逃脱父函数的另一种方式)。可以通过返回的引用调用任何一个内部函数:

  1. (1) outerVar = 1
  2. (2) outerVar = 3
  3. (1) outerVar = 4
  4. (1) outerVar = 1
  5. (2) outerVar = 3
  6. (1) outerVar = 4

这两个内部函数引用了同一个局部变量,因此它们共享同一个封闭环境。当innerFn1()outerVar递增1时,就为调用innerFn2()设置了outerVar的新的起点值,反之亦然。同样,我们也看到对outerFn()的后续调用还会创建这些闭包的新实例,同时也会创建相应的新封闭环境。面向对象编程的爱好者们会注意到,这在本质上是创建了一个新对象,自由变量就是这个对象的实例变量,而闭包就是这个对象的实例方法。而且,这些变量也是私有的,因为不能在封装它们的作用域外部直接引用这些变量,从而确保了面向对象的数据专有特性。