闭包
概念
只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁
例子
1function outer(){ 2 var localVal = 30; 3 return localVal; 4} 5 6outer();//30 7 8function outer(){ 9 var localVal = 30; 10 return function() { 11 return localVal; 12 } 13} 14 15var func = outer(); 16func();//30
作用:比如在一个函数中嵌套一个函数,通过闭包可以让嵌套函数访问到包裹它的函数的局部变量。
封装
1(function(){ 2 var _userId = 123; 3 var _typeId = 'item'; 4 var MyExport = {}; 5 6 function converter(userId){ 7 return + userId; 8 } 9 10 MyExport.getUserId = function(){ 11 return converter(_userId); 12 } 13 14 MyExport.getTypeId = function(){ 15 return _typeId; 16 } 17 window.MyExport = MyExport; 18})(); 19 20MyExport.getUserId();//123 21MyExport.getTypeId();//item 22 23MyExport._uerId;//undefined 24MyExport._typeId;//undefined 25MyExport.converter;//undefined
闭包陷阱
1var tasks = []; 2 3for (var i=0; i<3; i++) { 4 tasks.push(function() { 5 console.log('>>> ' + i); 6 }); 7} 8 9console.log('end for.'); 10 11for (var j=0; j<tasks.length; j++) { 12 tasks[j](); 13}
输出结果都为3。这个问题的原因在于,函数创建时并未执行,所以先打印end for.,然后才执行函数,由于函数引用了循环变量i,而i的作用域是整个函数,而不是循环,在函数执行时,i的值已经变成了3。
解决方法
再创建一个函数,将循环变量作为函数参数传入:
1var tasks = []; 2 3for (var i=0; i<3; i++) { 4 var fn = function(n) { 5 tasks.push(function() { 6 console.log('>>> ' + n); 7 }); 8 }; 9 fn(i); 10} 11 12//简化语法,直接用匿名函数的立即执行模式(function() { ... })() 13 14var tasks = []; 15 16for (var i=0; i<3; i++) { 17 (function(n) { 18 tasks.push(function() { 19 console.log('>>> ' + n); 20 }); 21 })(i); 22}
总结
优点:灵活方便,封装
缺点:空间浪费,内存泄漏,性能消耗