闭包
- 闭包
(1)闭包的概念
1) 但凡内部函数被保存到外部,必定产生闭包
2) 代码说明
|
function a(){ function b(){ var bbb = 234; document.write(aaa); //123 } var aaa = 123; return b; } var glob = 100; var demo = a(); demo();
|
(2) 闭包导致的问题:
3) 闭包会导致作用域链不释放,造成内存泄漏(占内存空间)
4) 对于上述代码来说就会导致b函数永久存在
(3)闭包的作用:
5) 实现累加器
|
Html |
|
<button onclick="counter()">累加</button>
|
|
Javascript |
|
function add(){ var count = 0; function test(){ count++; console.log(count); } return test; } var counter = add();
|
6) 可以做缓存(存储结构)
|
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('apple'); eater1.eat(); // I am eating apple
|
7) 可以实现封装,属性私有化
8) 模块化开发,防止污染全局变量
(4)闭包其他代码说明
|
代码一 |
|
function a(){ var num = 100; function b(){ num++; console.log(num); function c(){ num++; console.log(num); } return c; } return b; } var demo1 = a(); var demo2 = demo1(); demo2();
|
|
代码二 |
|
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 arr[1](); //100
//a函数和b函数形成的闭包拿到的是test函数的同一个执行上下文(AO)
|
- 闭包经典问题说明与解决方案
|
闭包经典问题 |
|
function test(){ var arr = []; for( var i = 0; i < 10; i++ ){ arr[i] = function (){ console.log(i); //10 } } return arr; } var myArr = test(); console.log(myArr); for( var j = 0; j < myArr.length; j++ ){ myArr[j](); //打印输出10个10 }
|
|
闭包经典问题说明 |
|
代码说明:为什么会打印输出10个10 数组中的函数与test函数形成闭包,该函数中的要打印的i来自于test函数中的执行 上下文(AO)中的i,而此时test函数中的AO中的i已经变成10了
数组中的i在变化时,因为数组后的函数并没有执行,因此函数体里面的i是不会变的 而当把数组保存到外部时,再当执行这个函数时,test函数已经执行完了,它会销毁自己的 AO,而保存到外部的数组函数会拿着test函数的AO,此时再回去打印这个i,而此时它回去到 它拿来的test函数中的AO中去找这个i,而此时这个i已经变成10了
|
|
闭包经典问题解决方案 |
|
function test(){ var arr = []; for( var i = 0; i < 10; i++ ){ (function (j){ arr[j] = function (){ console.log(j); } }(i)) } return arr; } var myArr = test(); console.log(myArr); for( var j = 0; j < myArr.length; j++ ){ myArr[j](); //打印输出0,1,2,3,4,5,6,7,8,9 }
|
|
闭包经典问题解决方案说明 |
|
解决闭包经典问题的方法:立即执行函数
立即执行函数执行完成后会被销毁,但是这销毁是销毁它的引用
在for循环里面放上立即执行函数,也就是生成10个立即执行函数 每个立即执行函数里面都有一个不同的i(0-9),并且把这个i赋给 其形参j,因此这个数组里面每次的j都会被拿到从而存放到数组里面 去;当最后执行这个数组中的每一个函数时,这个j就是相对应的
arr[j] = function (){ console.log(j); } 这个里面的函数拿走了立即执行函数(function (j){ arr[j] = function (){ console.log(j); } }(i)) 的AO 所以它里面打印的那个j就是立即执行函数AO中的j
|
- 闭包问题的进一步说明
(1)内存泄漏
内存泄漏的越多,内存剩的就越少,也就是内存被占用的越多,可用的就越少。(好比手攥沙子,攥得越紧,流的越多,内存占用就越多;手里剩的越少,剩下的可用内存就越少)
(2)一旦一种复杂形式的表达式执行后,它就会失去对原来函数的索引,它也就变成一次性的了,这也就是立即执行函数的雏形(第九章初见闭包和立即执行函数的第二个立即执行函数的补充说明的第六个内容有具体代码说明)
|
代码说明 |
|
|
(3)(function (){
console.log(‘a’); 数学符号(括号)
}())
执行符号
数学符号的优先级大于执行符号
- 其他问题的补充说明
(1)逗号操作符
1)有(两个或多个表达式被逗号隔开)先看前面的表达式,如果前面的表达式需要计算,那么进行计算;
2)再看后面的表达式,如果后面的表达式需要计算,那么进行计算
3)最后把后面的表达式的计算结果返回
4)代码说明
|
var f = ( function f(){ return "1"; }, function g(){ return 1; } )();
console.log(typeof f); //'number'
//不管这个f变量在预编译时会不会被f函数所替换,最后都会把这个数字1返回到f变量中
|
(2)括号会把括号里面的东西转换成表达式
|
代码说明 |
|
var x = 1; // function f(){}; if( function f(){} ){ //( function f(){} ) f函数在括号里面(隐式类型转换),会转换成表达式,那个f函数就不存在了 x += typeof f; } console.log(x); //'1undefined'
|
- 闭包经典例题
|
function fun(n, o) { console.log(o); return { fun: function (m) { return fun(m, n); } }; } var a = fun(0); a.fun(1); a.fun(2); a.fun(3); var b = fun(0).fun(1).fun(2).fun(3); var c = fun(0).fun(1); c.fun(2); c.fun(3);
//问:三行a,b,c的输出分别是什么?
console.log(a,b,c);
/* a:undefined 0 0 0 b:undefined 0 1 2 c:undefined 0 1 1 */
|
浙公网安备 33010602011771号