定义
? 一个函数和对其周围状态(词法环境)的引用捆绑在一起,这样的组合就是闭包。也就是说,闭包让你可以再一个内层函数中访问到其外层函数的作用域。在js中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
词法作用域
function init() {
var name = "Mozilla";
function displayName() {
alert(name);
}
displayName();
}
init();
闭包
例一:
function makeFunc(){
var name = 'hahaha';
function displayName(){
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
思考: makeFunc()执行完毕,代码仍然按照预期运行,myFunc 函数相当于displayName 函数绑定着var name = 'hahaha' 被返回出来了。
例二:
function add(x){
return function(y){
return x + y;
}
}
var add5 = add(5);
var add10 = add(10);
console.log(add5(1));
console.log(add10(2));
例三:闭包模拟私有方法
var counter = (function(){
var private = 0;
function change(val){
private += val;
}
return {
increment:function(){
change(1);
},
decrement:function(){
change(-1);
},
value:function(){
return private;
}
}
})();
console.log(counter.value());
counter.increment();
console.log(counter.value());
counter.decrement();
console.log(counter.value());
思考:每个闭包都有它自己的词法环境,例子中我们只创建了一个词法环境,为三个函数共享:counter.increment , counter.decrement , counter.value ,该环境创建于一个立即执行的函数内部,有一个私有变量private ,一个私有函数change , 他们不能在函数外面访问,只能通过 return出去的三个函数访问,这个三个return出去的函数是共享同一个环境的闭包。
例三的扩展:
var counter = function(){
var private = 0;
function change(val){
private += val;
}
return {
increment:function(){
change(1);
},
decrement:function(){
change(-1);
},
value:function(){
return private;
}
}
};
var counter1 = counter();
var counter2 = counter();
console.log(counter1.value());
counter1.increment();
counter2.increment();
console.log(counter1.value());
counter1.decrement();
console.log(counter1.value());
console.log(counter2.value());
例四:使用闭包解决for循环问题
for (var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i)
},0)
}
思考:因为var没有块级作用域,使用setimeout后,宏任务执行console.log的时候,i在主线程结束时候已经变成了5。
解决方法
for (var i = 0; i < 5; i++) {
let time = function(x){
setTimeout(() => {
console.log(x)
},0)
};
time(i);
}
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(x)
},0)
}
例五 理解迭代器原理
function iterator (items) {
let i = 0;
return function () {
return items[i++]
}
}
var next = iterator( [1, 2, 3, 4] );
console.log(next());
console.log(next());
console.log(next());
console.log(next());
console.log(next());
|