1. 什么是闭包
闭包就是能够读取其他函数内部变量的函数。
例:
function fun(){ var a = 10;//fun函数作用域内部的变量 return function(){ return a;//在此可以访问到fun函数作用域的a } } var geta = fun(); var a = geta(); console.log(a);//通过闭包我们就可以在fun函数外部访问到fun函数内部作用域的变量
在这个例子中,logA()就是一个闭包。
2. 闭包的用途
闭包的作用:
读取函数内部的变量;
将变量的值始终保持在内存中,不会在外层函数调用后被自动清除。
怎么来理解这句话呢?请看下面的代码。
function add () { var counter = 0; return function () { counter+=1; console.log(counter); } } add()();//1 add()();//1 add()();//1 var f=add(); f();//1 f();//2 f();//3
这里 内部的function是闭包,当你return该函数的时候,就被赋给了一个全局变量,这导致它始终在内存中,而它的存在依赖于add,因此add也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
但是:
function add () { var counter = 0; return function () { console.log(counter); } counter+=1; } var f=add(); f();//1 f();//1 f();//1 //均输出1
3. 闭包中的this问题
代码来自阮大大的思考题
代码片段一。
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()());
答案:输出The window
解析:object.getNameFunc()();这个语句是将闭包函数复制给全局变量,类似:
var f=object.getNameFunc(); f();
这里的f()属于全局变量。
代码片段二。
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()());
答案:输出My Object;
解析:这里使用that保存了object的this
闭包的使用场景
- 解决索引值问题
ar data = []; for (var i = 0; i < 3; i++) { //这里是函数 data[i] = function () { console.log(i); }; } data[0](); //3 data[1](); //3 data[2](); //3
改进:
var data = []; for (var i = 0; i < 3; i++) { //这里自执行函数 data[i] = ( function () { console.log(i); } ) (i); } data[0](); //3 data[1](); //3 data[2](); //3
- 私有成员的存在
var fun= (function () { var a =1 ; function f1 () { a++; console.log(a) }; function f2() { a++; console.log(a) }; return { b:bbb, c:ccc } })() // aaa.b()//2 // aaa.c()//3 // aaa.b()//4 // aaa.c()//5
- 闭包应用场景之setTimeout
//原生的setTimeout传递的第一个函数不能带参数 function fun(a){ console.log(a); } setTimeout(fun(1),1000);//立即执行,并没有1秒后执行。 //通过闭包可以实现传参效果 function func(a){ return function(){ alert(a) } } var f1 = func(1); setTimeout(f1,1000);//1秒后执行
- 封装变量,收敛权限
function isFirstLoad(){ var list=[]; return function(option){ if(list.indexOf(option)>=0){ //检测是否存在于现有数组中,有则说明已存在 console.log('已存在') }else{ list.push(option); console.log('首次传入'); //没有则返回true,并把这次的数据录入进去 } } } var ifl=isFirstLoad(); ifl("zhangsan"); ifl("lisi"); ifl("zhangsan");