个人理解闭包的产生主要就是:一切最外部的函数比里面的函数先执行,必然产生闭包,闭包会导致原有的作用域链不释放,造成内存泄漏
例子1
解析:实现上现在的demo保存的是function b() a执行之后就销魂了自身的AO,但是此时b已经保存了a的AO
<script>
function a() {
var num = 100;
function b() {
num++;
console.log(num);
}
return b; //b还没有被立即执行就直接返回了
}
// a先执行完 执行完销毁自身的ao
var demo = a();
demo(); //101
demo(); //102
demo(); //103
</script>
<!-- 等同于 -->
<!-- <script>
function a() {
var num = 100;
// function b() {
// num++;
// console.log(num);
// }
// b(); //101
// b(); //102
// b(); //103
for (var i = 0; i < 3; i++) {
function b() {
num++;
console.log(num);
}
b();
}
}
a();
</script> -->
例子2
解析:为什么可以打印出123?因为函数内部的b函数并没有执行而是被保存到了外部,a函数先执行此时的aaa已经是123了,b又保存了a的执行期上下文
<script>
function a() {
function b() {
console.log(aaa);
}
var aaa = 123;
return b;
}
var result = a();
result(); //123
</script>
例子3
<script>
function text() {
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = function () {
console.log(i);
} //还没执行 这一步就是相当于赋值 此时console.log(i)里的i看成一个i变量就行 等函数执行的时候再从作用域链里拿值
}
return arr;
}
var myarr = text();
myarr[0](); //10
myarr[1](); //10
myarr[2](); //10
// 分析:text()先执行的然后销毁了自身的AO,arr里的函数已经保留了text()里的AO,arr里的函数执行时从作用域里找i,找到9的时候还能进行循环 然后i++变成10直接return了
</script>
闭包的作用
1.实现共有变量(函数累加器)
// 1111111111111111.
function add() {
var num = 0;
function demo() {
num++;
console.log(num)
}
return demo();
}
var result = add();
result();
result();
2.可以做缓存
<script>
// 2222222222222222. 缓存结构
function test() {
var num = 100;
function a() {
num++;
console.log(num)
}
function b() {
num--;
console.log(num)
}
return [a, b];
}
var arr = test();
arr[0](); //101 先执行a()
arr[0](); //102
arr[1](); //101 执行b() 拿到的num是已经改过的num
</script>
3.可以实现封装,属性私有化
<script>
function eater() {
var food = "";
var obj = {
eat: function () {
console.log("i am eating " + food)
},
food: "",
push: function (myfood) {
food = myfood;
}
}
return obj;
}
var eater1 = eater();
eater1.push('tea');
eater1.eat(); // eat() i am eating tea
</script>
4.模块化开发,防止污染全局变量
<script>
var name = 'hhh';
var init = (function () {
var name = 'abc';
function callname() {
console.log(name);
}
return function () {
callname();
}
}())
var initha = (function () {
var name = 'tt';
function callname() {
console.log(name);
}
return function () {
callname();
}
}())
init(); //abc
initha() //tt
</script>
闭包的解决方法
1.立即执行函数
function text() {
var arr = [];
for (var i = 0; i < 10; i++) {
(function (a) {
arr[a] = function () {
console.log(a);
} //保存的是立即执行函数的成果AO()
}(i))
}
return arr;
}
var myarr = text();
myarr[0](); //0
myarr[1](); //1
myarr[2](); //2
2.ES6 let声明变量----let定义变量
function text() {
var arr = [];
for (let i = 0; i < 10; i++) {
arr[i] = function () {
console.log(i);
}
}
return arr;
}
var myarr = text();
myarr[0](); //0
myarr[1](); //1
myarr[2](); //2