闭包:(闭包找的是同一地址中父级函数中对应变量最终的值)
一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
闭包特点
1.函数嵌套函数
2.内部函数引用外部函数的变量或者形参
3.被引用的变量或者形参可以常驻内存
function aaa(a){
var b = 20;
function bbb(){
console.log(a,b); //闭包
}
return bbb;
}
var ccc = aaa(10);
console.log("aaa函数执行完毕,被回收");
ccc(); //10,20
好处:
1.有一个变量常驻在内存当中
2.避免全局变量污染
3.通过外部无法访问到内部数据
var a = 2; //全局变量被污染
function show(){
a++;
console.log(a);
}
show(); //3
show(); //4
function show(){
var a = 2;
a++;
console.log(a);
}
show(); //3
show(); //3
console.log(a); //报错 a is not defined 因为垃圾回收机制 show()函数被回收了
既要保存之前调用结果,还要不污染全局变量。
让这个变量常驻内存,就是闭包。
function aaa(){
var a = 2; //被创建的一个局部变量
function bbb(){ //函数中嵌套函数,所以这是个闭包
a++; //对父函数中的变量进行运算
console.log(a);
}
return bbb;
}
var ccc = aaa();
ccc(); //3
ccc(); //4
console.log(a); //a is not difined 因为闭包内的变量外部是无法访问的
aaa() 创建了一个局部变量 a 和一个名为 bbb() 的函数。bbb() 是定义在aaa() 里的内部函数,并且仅在 aaa() 函数体内可用。请注意,bbb() 没有自己的局部变量。然而,因为它可以访问到外部函数的变量,所以 bbb() 可以使用父函数 aaa() 中声明的变量 a ,又因为闭包的原因所以bbb()中a++后的值会被保存下来,最后通过return又返回给父函数,从而改变父函数中声明的局部变量,so最终的结果就是代码3,4
上述代码的立即执行函数写法:var ccc = (函数声明)(函数调用)
var ccc = (function(){
var a = 2;
return function(){
a++;
console.log(a);
}
})();
ccc(); //3
ccc(); //4
弊端:
在IE浏览器下会引发内存泄漏
window.onload = function(){
var div = document.getElementById("...")
div.onclick = function(){
//在IE下的div这个变量中由于通过闭包调用,不会释放,所以会造成内存泄漏
alert(div.id)
}
}
解决方法
window.onload = function(){
var div = document.getElementById("...");
var id = div.id;
div.onclick = function(){
alert(id);
}
//div 所占的内存就被释放掉了
div = null;
【注】事实上,通过使用闭包,我们可以做很多事情。比如模拟面向对象的代码风格;利用闭包来进行模块化的开发;更优雅,更简洁的表达出代码;在某些方面提升代码的执行效率,同时避免对命名空间的污染,最重要的是可以从一个域中取出原本访问不到的变量去使用。
利用闭包来进行模块化的开发:
弊端:
无法进行二次开发
解决方法:
一:放大模式 【注】本地存储的时候会有加载顺序的问题,服务器上会有加载延迟的问题导致原本顺序错误
二:宽放大模式
var moduleA = (function (mod) {
function showC() {
console.log("我是showC");
}
mod.outC = showC;
return mod;
})(moduleA || {});
//如果先执行的这个,那么这个函数中开始的时候mod是没有值的,所以调用的是一个空对象,
//接下来执行函数,最后返回一个mod值,以备待用
当上面的代码执行完毕后里面已经有值了,所以下面的代码可以直接调用moduleA方法,最终moduleA对外暴露时既有C的值也有A,B的值。同理如果这两个代码顺序颠倒,也不会影响最终输出的结果
var moduleA = (function (mod) {
var count = 10; //私有变量
function showA() {
//私有方法
count++;
console.log(count);
}
function showB() {
count *= 10;
console.log(count);
}
mod.outA = showA;
mod.outB = showB;
return mod;
})(moduleA || {});
例子
例1
function fn(){
var a = 3;
return function(){
return ++a;
}
}
alert(fn()()); //4
alert(fn()()); //4
例2
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc(); //Mozilla