首页 > 代码库 > 《JavaScript设计模式与开发》笔记 4.闭包
《JavaScript设计模式与开发》笔记 4.闭包
- 1.变量的作用域
- 2.变量的生存周期
- 3.闭包更多作用
- 1.封装变量
- 2.延续局部变量寿命
- 4.闭包和面向对象设计
- 5.闭包和内存管理
1.变量的作用域
var func = function(){ var a = 1;}func();console.log(a); //输出undefinedvar a = 1;fun1 = function(){ var b = 2; fun2 = function(){ var c = 3; console.log(b); //输出 2 console.log(a); //输出 1 } fun2(); console.log(c); //输出undefined}fun1();
2.变量的生存周期
var func = function(){ var a = 1; return function(){ a++; console.log(a); }}var f = func();f(); // 输出1f(); // 输出2f(); // 输出3f(); // 输出4
当退出函数后,局部变量a并没有消失,而是似乎一致在某个地方存活着。这是因为当执行var f = func();
时,f返回了一个匿名函数的引用
,它可以访问到func()被调用时产生的环境,而局部变量a一致处于这个环境里。既然局部变量所在的环境还能被外界,这个局部变量就有了不被销毁的理由。这里产生了一个闭包结构,局部变量的声明看起来被延续了。
既然f返回了一个匿名的函数引用,那么下面的也符合闭包
var func = (function(){ var a = 1; return function(){ a++; console.log(a); }})();f(); // 输出1f(); // 输出2f(); // 输出3f(); // 输出4
再次变种为引用对象的方式
var func = { a :0, call:function(){ this.a++; console.log(this.a); }}func.call(); //输出1func.call(); //输出2func.call(); //输出3
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><script> var nodes = document.getElementsByTagName(‘div‘); for(var i =0;i<nodes.length;i++){ nodes[i].onclick=function(){ alert(i); } }</script></body></html>
测试这段代码就会发现,无论点击哪个div,最后弹出的结构都是5,。这是因为div节点onclick事件是被异步出发的,当事件出发的时候,for循环早已结束,此时变量i的值已经是5,所以在div的onclick事件函数中顺着作用域链从内到外查找变量i时,查找到的值总是5。
解决方法是在闭包作用的帮助下,把每次循环的i值都封装起来。(就是把每个点击事件都独立放在内存里面。)
var nodes = document.getElementsByTagName(‘div‘); for(var i =0;i<nodes.length;i++){ (function(i){ nodes[i].onclick=function(){ alert(i); } })(i); }
3.闭包更多作用
1.封装变量
闭包可以帮组我们封装私有变量”
var mult = function(){ var a = 1; for(var i =0;i <arguments.length;i++){ a = a*arguments[i]; } return a;}console.log(mult(1,2,5));
mult函数接受一些number类型的函数,并返回这些参数的乘积。现在我们觉得对于这些那些参数来说,每次都进行计算是一种浪费,我们可以加入缓存机制来提高这个函数的性能。
var cache={};var mult = function(){ var args = Array.prototype.join.call(arguments,‘,‘); //将参数对象变成一个字符串 args 1,2,3 if(cache[args]){ console.log(‘执行缓存‘); return cache[args]; } var a = 1; for(var i=0;i<arguments.length;i++){ a = a*arguments[i]; } return cache[args] = a;}console.log(mult(1,2,3)); //进行计算console.log(mult(1,2,3)); //执行缓存,不用计算
继续封装减少页面全局变量
var mult = (function(){ var cache={}; //私有变量 return function(){ var args = Array.prototype.join.call(arguments,‘,‘); if(cache[args]){ return cache[args]; } var a = 1; for(var i=0;i<arguments.length;i++){ a = a*arguments[i]; } return cache[args] = a; }})()console.log(mult(1,2,3)); //进行计算console.log(mult(1,2,3)); //执行缓存,不用计算
提炼代码,独立模块
var mult = (function(){ var cache={}; //私有变量 var cala = function(){ var a = 1; for(var i=0;i<arguments.length;i++){ a = a*arguments[i]; } return a; } return function(){ var args = Array.prototype.join.call(arguments,‘,‘); if(cache[args]){ return cache[args]; } return cache[args] = cala.apply(null,arguments); }})();console.log(mult(1,2,3)); //进行计算console.log(mult(1,2,3)); //执行缓存,不用计算
2.延续局部变量的寿命
var report = function(src){ var img = new Image(); img.src = src;}
利用闭包来延续img的使用
var report = (function(){ var imgs = []; //img就留在了内存里面 return function(src){ var img = new Image(); imgs.push(img); img.src = src; }})();
4.闭包和面向对象
闭包:
var extent = function(){ var value =http://www.mamicode.com/0; return { call:function(){ value++; console.log(value); } }}var extent = extent();extent.call(); //输出1extent.call(); //输出2extent.call(); //输出3
如果换成面向对象的写法就是
var extent = { value :0, call:function(){ this.value++; console.log(this.value); }}extent.call(); //输出1extent.call(); //输出2extent.call(); //输出3
5.闭包和内存管理
闭包是一个非常强大的特性,但人民对其他诸多误解,一种耸人听闻的说法就是闭包会造成内存泄漏。如果在将来需要回收这些变量,我们可以手动吧这些变量设置为null。
《JavaScript设计模式与开发》笔记 4.闭包
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。