简单解释闭包就是能够读取其它函数内部变量的函数。它的两个最大用处:可以读取函数内部的变量让这些变量的值始终保持在内存中

js中变量作用域分为: 全局变量 和 局部变量,JS的特殊之处在于:每个函数都会创建一个新的作用域,函数内部可以读取外部变量,而函数外部无法读取内部变量

创建:只要在一个函数中再定义一个函数,这个内部函数就是一个闭包

function foo() {//这是普通内部函数访问外部变量。执行console.log()时,在bar作用域没找到a,去上一级foo作用域找到,所以输出2。
  var a = 2;
  function bar() {
    console.log( a );
  }
  bar();
}
foo();//2

function foo() {//这是闭包,todo函数访问到了bar函数作用域变量a。执行 foo() 时,其实将函数 bar() 作为值引用类型传递给了 todo,当执行 todo() 时 等于执行了 bar()。

  var a = 2;

  function bar() {

    console.log( a ); // 2

  }

   return bar;

}

var todo = foo();

todo(); // 2

闭包的常用例子:

for(var i = 0; i < 3; i++ ){//每隔一秒循环打印
  (function(x){ setTimeout(function(){
    console.log(x) },x*1000) })(i)
}

将变量始终保存在内存中:

function foo() {//函数bar被赋给了一个全局变量,这导致函数bar始终在内存中,而bar的存在依赖于foo,因此foo也始终在内存中。add是一个全局变量,它的值是一个匿名函数也是一个闭包。

  var a = 2;

  function bar() {

    console.log( a ); // 2

  }

  add=function(){a+=1;}

   return bar;

}

var todo = foo();

todo(); // 2

add();

todo();

闭包中使用this对象可能会导致一些问题。因为匿名函数的执行具有全局性,因此其this对象通常指向window

var name = "The window";
var object = {
  name:"My object",
  getNameFun:function(){
    return function(){
      return this.name;
    };
  }
};
alert(object.getNameFun()()); //"The window"(在非严格模式下)
解决方法:把外部作用域中的this对象保存在一个闭包能够访问的变量里面(留住this)。
var name = "The window";
var object = {
  name:"My object",
  getNameFun:function(){
  var that = this;
  return function(){
    return that.name;
    };
  }
};
alert(object.getNameFun()()); //“My object”
闭包的内存泄漏(该内存空间使用完毕之后未回收)
function Cars(){
  this.name = "Benz";
  this.color = ["white","black"];
}
Cars.prototype.sayColor = function(){
  var outer = this;
  return function(){
    return outer.color
  };
};
var instance = new Cars();
console.log(instance.sayColor()())
优化后代码:
function Cars(){
  this.name = "Benz";
  this.color = ["white","black"];
}
Cars.prototype.sayColor = function(){
  var outerColor = this.color; //保存一个副本到变量中
  return function(){
    return outerColor; //应用这个副本
  };
  outColor = null; //释放内存
};
 
var instance = new Cars();
console.log(instance.sayColor()())