当内部函数被返回到外部并被保存时,一定会产生闭包现象,闭包会导致内部函数的作用域链不释放(外部词法环境不随着执行上下文销毁而销毁),过度的闭包可能导致内存泄漏或加载过慢。
比如以下代码,将test2作为返回值赋值给test3,此时test2函数便可以一直钩住test1的词法环境,拿到它环境中的变量、函数。
function test1(){
function test2(){
var b = 2;
console.log(a);
}
var a = 1;
return test2;
}
var test3 = test1();
test3(); // 1
闭包与IIFE
此处内部函数arr[i]并没有执行,闭包现象拿到了i的最终值是10,所以打印出的都是10。
function test(){
var arr = [];
// 相当于是 var i = 0;
for(var i = 0; i < 10; i++){
arr[i] = function(){
document.write(i + ' ');
}
}
return arr;
}
var myArr = test();
for(var j = 0; j < 10; j++){
myArr[j]();
}
// 10 10 10 10 10 10 10 10 10 10
此处内部函数是立即执行函数,所以打印出的都是当前循环出的i值。
function test(){
for(i = 0; i < 10; i++){
(function(){
document.write(i + ' ');
})();
}
}
test();
此处参与循环的函数是立即执行函数,每次循环时,i值作为实参被保存进了立即执行函数中,之后内部函数调用拿到的i值都是立即执行函数当时保存的i值。
function test(){
var arr = [];
for(i = 0; i < 10; i++){
(function(j){
arr[j] = function(){
document.write(j + ' ');
}
})(i);
}
return arr;
}
var myArr = test();
for(var j = 0; j < 10; j++){
myArr[j]();
}
闭包实现累加器
// 累加器
function test1(){
var num = 0;
function test2(){
num++;
console.log(num);
}
return test2;
}
var add = test1();
add(); // 1
add(); // 2
add(); // 3
闭包实现增删改查
function class1(){
var name = [];
var methods = {
add: function(i){
name.push(i);
console.log(name);
},
leave: function(j){
name.splice(j, 1);
console.log(name);
}
}
return methods;
}
demo = class1();
demo.add("小明");
demo.add("小红");
demo.add("小方");
demo.add("小白");
demo.leave(1);