# JavaScript 闭包

# 闭包

闭包可以让一个函数访问并操作其声明时的作用域中的变量和函数,并且,即使声明时的作用域消失了,也可以调用

复杂的解释:

闭包就是由函数创造的一个词法作用域,里面创建的变量被引用后,可以在这个词法环境之外自由使用。 闭包通常用来创建内部变量,使得这些变量不能被外部随意修改,同时又可以通过指定的函数接口来操作。

最简单的闭包

// 全局作用域就是一个闭包
var outerVal = 'lionel';
function outerFn(){
  console.log(outerVal)
}
outerFn() // lionel

私有变量

闭包常见的用法,封装私有变量。用户无法直接获取和修改变量的值,必须通过调用方法;并且这个用法可以创建只读的私有变量

function People(num) { // 构造器
  var age = num;
  this.getAge = function() {
    return age;
  };
  this.addAge = function() {
    age++;
  };
  console.log(this)
}

绑定函数上下文

Function.prototype.myBind = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('Error');
  }
  var _this = this;
  var args = [...arguments].slice(1);
  
  // 返回一个函数
  return function F() {
    // 因为返回了一个函数,我们可以 new F(),所以需要判断
    if (this instanceof F) {
      return new _this(...args, ...arguments);
    }
    return _this.apply(context, args.concat(...arguments));
  }
}

缓存记忆 利用闭包来实现一个memoize函数

# 循环和闭包

for(var i = 0; i < 5; i++) {
  setTimeout(function timer() {
    console.log(i);
  }, 1000);
}
//输出: 一秒后,连续输出5个5
for(var i = 0; i < 5; i++) {
  (function() {
    setTimeout(function timer() {
      console.log(i);
    }, 1000);
  })();
}
//输出: 一秒后,连续输出5个5
for(var i = 0; i < 5; i++) {
  (function(j) {
    setTimeout(function timer() {
      console.log(j);
    }, 1000);
  })(i);
}
//输出: 一秒后,连续输出0,1,2,3,4
for(let i = 0; i < 5; i++) {
  setTimeout(function timer() {
    console.log(i);
  }, 1000);
}

//使用了let声明
//输出: 一秒后,连续输出0,1,2,3,4
for(var i = 0; i < 5; i++) {
  (function(j) {
    setTimeout(function timer() {
      console.log(j);
    }, 1000 * j);
  })(i);
}
//输出:每隔一秒,输出0,1,2,3,4

# 模块和闭包

function CoolModule() {
  let something = "cool";
  let another = [1, 2, 3];

  function doSomething() {
    console.log(something);
  }

  function doAnother() {
    console.log(another.join("!"));
  }

  return {
    doSomething: doSomething,
    doAnother: doAnother
  };
}

var foo = CoolModule();
foo.doSomething();//cool
foo.doAnother();//1!2!3

# 使用闭包注意

1.由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除

# 应用

  1. 私有变量
  2. 回调与计时器
  3. 绑定函数上下文
  4. 偏应用函数
  5. 函数重载:缓存记忆、函数包装
  6. 即时函数:独立作用域、简洁代码、循环、类库包装、通过参数限制作用域内的名称
陕ICP备20004732号-3