每次回顾知识点都有不同的收获,对于前端程序原来说,闭包是个难懂又必须弄懂的概念。闭包的形成与变量的作用域及变量的生存周期密切相关。在此之前 先简单了解下这两个知识点
var a= 1 var fun1 = function(){ var b = 2 var fun2 = function (){ var c = 3 alert(b) // 2 alert(a) // 1 } fun2() alert(c) // c is not defined } fun1()
var func = function(){ var a = 1 return function(){ a++ alert(a) } } var f=func() f() //2 f() //3 f() //4 f() //5
跟我们之前的理论相反,在推出函数后,局部变量并没有被注销回收,类似 在某个地方存活着。
这是因为当我们执行 var f = func()时,f返回的是个匿名函数的引用,它可以访问 func()产生的环境变量a,而局部变量a 一直处于这个环境里。既然局部变量所在的环境还能被外界访问,这个局部变量就有了不被销毁的理由。在这里产生了一个闭包结构,局部变量的生命被延续了!!!
在我们工作中有许多地方用到闭包 让我们完成许多奇妙的工作。有这么个案例:页面上有五个一模一样的按钮,我们通过循环绑定click事件的方式,点击第一个 打印0 第二个1 依次类推。。
如果就简单的通过循环 for循环 进行绑定他们的索引值的话 结果发现 打印的都是5
解决方法:就是闭包 使用闭包 将每次循环索引值封闭起来。当点击事件触发的时候 顺着作用域链中从内到外查找,分别就是 0 、1、 2、 3、 4
var mult = function (){ var a = 1; for(var i= 0,l = arguments.length;i<l;i++){ a = a * arguments[i] } return a }
nult函数会接受一些number类型的参数 并返回这些参数的乘积,每次调用函数的 时候都会计算,为我们可以考虑下加个缓存机制来提高函数的性能
var cache = {} var mult = function (){ var args = Array.prototype.join.call(arguments,',') if(cache[args]){ return cache[args] } var a = 1; for(var i= 0,l = arguments.length;i<l;i++){ a = a * arguments[i] } return cache[args] = a }
以上添加了缓存机制,也在最大程度的优化了函数;下面面临着另一个问题 cache变与 mult函数一起平行的暴露在全局作用域中,cache变量 别的函数用不到 而且容易造成全局变量名的混乱,不如把他封装到mult函数内部,在一定程度上减少页面中的全局变量,也可避免这个变量在其他地方被不小心修改er引发的错误
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,l = arguments.length;i<l;i++){ a = a * arguments[i] } return cache[args] = a } })()
这种提炼代码也是代码重构中最常见的一种技巧。
如果在大函数中有一些代码块能够独立出来,我们常常吧这些代码块封装在独立的小函数里面;独立出来的小函数有助于代码的复用,有良好的命名的话 本身也起着注释的作用。
如果这些小函数不需要在程序的其他地方使用,最好是把它们用闭包封闭起来
var mult = (function(){ var cache = {} var calculate = function(){ var a = 1; for(var i= 0,l = arguments.length;i<l;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] = calculate.apply(null,arguments) } })()
var report = function( src ){ var img = new Image() img.src = src } report('baidu.com')
上面代码在一些低版本浏览器的实现上存在bug,report 函数会丢失数据,并不是每次report函数都能成功的发送http请求。丢失的原因是 img是report的局部变量,当report函数执行完毕后 img局部变量会进行销毁,从而导致数据丢失的问题
修复下:
var report = (function( src ){ var imgs = [] return function(src){ var img = new Image() imgs.push(src) img.src = src } })()
参考文献:JavaScript设计模式与开发实践