js的闭包,简单来说就是提供了一个在外部访问另一个函数内部局部变量的方式。
先写一个常见的例子:
1 2 3 4 5 6 7 8 9 10 |
var add = (function () { var counter = 0; return function () {return counter += 1;} })(); add(); add(); add(); // 计数器为 3 |
注意: 为什么上面这段代码没有直接写的 function add (){…} 而是把function赋值给了变量add呢?
我们通常会想当然的认为每次调用 add() 都会重走一遍add()中的代码块, 但其实不然。
注意add方法中的return, 它return的并不是1,2,3这样的数值,而是return了一个方法,并且把这个方法赋值给了add变量。
那么在这个function自运行一遍之后,其实最后赋值给add的是return counter += 1 这段代码。
所以后面每次调用add() 其实都是在调用return counter += 1。
再结合文章之前所说的, 闭包会持有父方法的局部变量并且不会随父方法销毁而销毁, 所以这个counter其实就是来自于第一次function执行时创建的变量。
最后这句是关键
所以可以这样转变思路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
function outerFunction() { var counter = 0; function innerFunction(){ return counter += 1; } return innerFunction; /* 注意 typeof innerFunction 是:function;而typeof innerFunction()是number; */ } var add = outerFunction(); /* 调用 outerFunction()返回的是内部函数innerFucntion,那么调用几次add()将调用几次 内部函数inner Function,内部函数公用了counter,所以能够计数,所以说闭包就是将内部嵌套函数变成外部可调用的。 */ add(); add(); add(); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function fn(){ var arr=[]; //i为fn函数中的局部变量。 for(var i=0;i<3;i++){ arr.push(function(){ return i; }); } return arr; } var b=fn(); for(var i=0;i<b.length;i++){ console.log(b[i]());//3 } |
以上示例输出的结果均是3,也就是循环结束后i的值。这是因为在for循环的过程当中,数组中的匿名函数并没有自我执行。当在调用匿名函数的时候,通过闭包获得的i已经是3了,所以每次输出的都是3。
如果想要输出的结果为0,1,2可以做如下的调整:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function fn(){ var arr=[]; for(var i=0;i<3;i++){ arr.push((function(num){ //将立即执行函数返回的匿名函数放到数组中。 //因为num为函数的参数,因此有自己独立的作用域 return function(){ return num; }; })(i)); } return arr; } var b=fn(); for(var i=0;i<b.length;i++){ console.log(b[i]());//0,1,2 } |
通过匿名函数的立即执行,将立即执行后返回的函数直接赋值给数组arr。每次循环即将i的值传递给num,又因为num在函数中,所以有自己的独立作用域,因此num得到的值为每次循环传递进来的i值,即0,1,2
应用:一个是读取内部变量;二是延续局部变量的寿命,解决某些数据丢失的问题,也可以理解为封装私有变量或方法
缺点:(1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
(2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
参考
:
http://www.runoob.com/js/js-function-closures.html
https://www.jianshu.com/p/2fb8a9f26589