1.闭包的定义:
闭包是指有权访问另一个函数作用域中的变量的函数。——《JavaScript高级程序设计》
简单来说是保留了对自由变量的引用的函数。网上有人说:“闭包的中的闭是封闭外部状态,而非封闭内部状态。一个函数如何封闭外部状态呢,就是当外部scope失效时,还保留一份在内部状态里面。”
2.创建闭包的方式
创建闭包常见的方式就是在一个函数内部创建另一个函数。
例1:函数中的setTimeout
function outer(){
for(var i=0;i<5;i++){
setTimeout(function(){
console.log(i)
},100)
}
}例2:函数中的匿名函数
function outer(){
var inner = [];
for(var i=0;i<5;i++){
inner[i] = function(){
console.log(i)
}
}
return inner;
}
//如果是同一个对象的inner[i]中的i值会相互影响3.闭包的好处与坏处
好处:①保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突; ②在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存);③匿名自执行函数可以减少内存消耗
坏处:①其中一点上面已经有体现了,就是被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null; ②其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响
4.闭包的应用
①避免命名冲突
var global = "global";
var local = function(){
var global = "local";
return function(){
return global;
}
}()
console.log(global);//"global"
console.log(local());//"local"②保留辅助变量
function counter(){
var count = 0;
return function(){
return ++count;
}
}
var count1 = counter();
var count2 = counter();
console.log(count1());//1
console.log(count1());//2
console.log(count2());//1
//count1与count2不是同一个对象,count变化不会相互影响5.解决闭包的几种方式
①使用ES6中let声明变量
function outer(){
var inner = [];
for(let i=0;i<5;i++){
inner[i] = function(){
console.log(i)
}
}
return inner;
} ②添加立即执行函数
function outer(){
var inner = [];
for(var i=0;i<5;i++){
inner[i] = (function(num){
return function(){
console.log(num);
}
})(i)
}
return inner;
}或
function outer(){
var inner = [];
for(var i=0;i<5;i++){
(function(num){
inner[i] = function(){
console.log(num);
}
})(i)
}
return inner;
}③通过new Function
function outer(){
var inner = [];
for(var i=0;i<5;i++){
inner[i] = new Function("console.log("+i+");")
}
return inner;
}另外,网上有人提到可以为inner[i]添加属性,在function中返回该属性的值即可。
//该方法不可行,因为会被覆盖,若不是inner[i] = function,而是inner[i].fun = function则可行
function outer(){
var inner = [];
for(var i=0;i<5;i++){
inner[i].value = i;
inner[i] = function(){
console.log(this.value)
}
}
return inner;
}