闭包认知

· 3 min read

最近在梳理JS基础,觉得闭包这个知识点并不清晰,研究了会儿,所谓踏雪有痕,这里MARK下。

什么是闭包

函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成 闭 包(closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在 JavaScript 中,每当函数被创建,就会在函数生成时生成闭包。

摘自MDN

注意

  1. 函数作用域,不是块作用域
  2. 闭包是有状态的函数

先上几个例子,看看谁是闭包

例子1

   function init() {
        var name = 'Mozilla'; // name 是一个被 init 创建的局部变量
        function displayName() {
          // displayName() 是内部函数
          alert(name); // 使用了父函数中声明的变量
        }
        displayName();
      }
      init();

例子2

function makeFunc() {
    var name = "Mozilla";
    function displayName() {
        alert(name);
    }
    return displayName;
}
var myFunc = makeFunc();
myFunc();

TIP

注意,Chrome调试状态下是可以看出来谁是闭包的。有助于去理解。

通过这几个例子实际上可以这么去说

闭包即是可以访问其他函数作用域内变量的函数对象,同时你可以说闭包是有状态的函数

闭包的运用

知道谁是闭包,那么就是闭包可以干嘛。

  1. 封装私有变量
  2. 模块
  3. 用在块作用域上
  4. 监听器

这几种用法,我们只是有意无意的在使用,可能只是不知道而已。

闭包是一种技术,不限语言

如上,闭包Closure是一种技术手段,所以与语言无关,那么比如java有闭包吗。有的。

Java中的闭包

比如最常见的lambda中,我们传入传入外部函数变量,从而形成闭包。

int factor = 3;

numbers.stream()
  .filter(e -> e % 2 == 0)
  .map(e -> e * factor)
  .collect(toList());

为什么说这是个闭包,注意factor是函数外部的函数词法坏境

概念困惑 - lambda,匿名函数,闭包

  1. lambda即匿名函数,两个叫法而已
  2. 闭包跟匿名函数并不同,如上例子中,如果factor去掉,其实就不是闭包了

上题

闭包后,来看几道复杂点的题。

题1

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


// 第一个例子
var a = fun(0); // 返回undefined
a.fun(1); // 返回 0
a.fun(2); // 返回 0
a.fun(3); // 返回 0

// 第二个例子
var b = fun(0)
  .fun(1)
  .fun(2)
  .fun(3); // undefined,0,1,2

// 第三个例子
var c = fun(0).fun(1);
c.fun(2);
c.fun(3); // undefined,0,1,1

题2

   var myObject = {
        foo: 'bar',
        func: function () {
          var self = this;
          console.log('outer func:  this.foo = ' + this.foo);  // bar
          console.log('outer func:  self.foo = ' + self.foo);   // bar
          (function () {
            console.log('inner func:  this.foo = ' + this.foo); // unfefined
            console.log('inner func:  self.foo = ' + self.foo); // bar
          })();
        },
      };

      myObject.func();

  • 这道题理论上多个考察点就是this指向问题,记得以前看书时,有句话讲的很棒,this永远指向调用它的对象。比如这里就是myObject。
  • func及其

写在最后

编程界崇尚以简洁优雅为美,很多时候如果你觉得一个概念很复杂,那么很可能是你理解错了,这句话深表认同。带着这样的认识去看待诸如闭包这样的概念,我想应该会更简单些。

参考文档