javascipt-closure(闭包)
javascript充满神秘,至少对初学者来说是这样,在初学者的世界的上空,总是笼罩着几朵乌云,挥之不去;
我也是初学者,曾经头上也有closure、hoisting、function scope等明星乌云。
Function scope(函数作用域)
众所周知,java语言的作用域是block(就是一对花括号),在block中代码和变量处在同一个作用域(scope)中,作用域本身也可能处在父作用域中,子作用域的代码可以访问父作用域的,但是父作用域不能访问子作用域的。好吧,说起来可能绕一点(要不为啥文章开头要求你又java基础认识呢),举一个代码的例子吧:
public class Demo{
//scope1
public void foo(){
//scope2
}
}
这个熟悉吧,在java中最大的scope也就是class scope了,还记得么,在scope1中申请的变量叫做成员变量,在scope2中申请的变量叫做局部变量;
在javascript中,scope的界限就不是block了,而是function!!!(这我后来才知道的,汗),scope之间的访问关系还是和java一样,子能访父,反之不行。下面举一个function scope的小实例:
function outside(){
var out = "out var";
function inside(){
var in = "in var";
console.log(out); //out var
console.log(in); // in var
}
console.log(out); //out var
console.log(in); // b is not defined
}
可以看得出来,javascript的scope是function,不信的童鞋可以试试在if代码块中申请一个变量,在if代码块外打印一下,它会成功打印出来的。
废了一番大劲,终于讲好了js的function scope,下面就是重点了!!
Class和Closure
前面讲到过,java中以类为基本单位,类的结构虽然是封装起来的,但是可以用修饰符来提供对外界的访问;不同于java,javascript的scope中并没有提供修饰符供外界访问,但是所有的scope都会有一个全局变量window可以访问,这样scope就可以间接访问。他们看起来就像下面这样:

java中这么做的好处就可以将类看成一个模块,模块之间的内部不相干,更容易去构建出复杂有序的系统;
javascript应该向其学习,因为javascript的scope只能通过全局window来互相访问,而这是一个比较糟糕的地方。
下面开始举一个例子,首先由两个文件A.js和B.js,同时在c.html中被引入:
//c.html
.
//a.js 打印当前系统的版本
var version = "1.0.0";
function say(){
console.log(version);
}
.
//b.js 恰好这里有个变量也是version
var version = "2.0.0";
查看c.html的console打印,结果是"2.0.0",a.js和b.js同时在window变量上注册了version,造成了覆盖情况,很容易想象,如果一个多js文件的项目,各个文件之间为避免window覆盖注册就真够头疼的。
这时候我们可以想到用function scope,要是把a.js和b.js的代码写入到单独的function中就可以避开之间的影响。
//a.js
function a(){
var version = "1.0.0";
//如果外界要访问,可以return 出去
function say(){
console.log(version);
};
return say;
}
//b.js
function b(){
var version = "2.0.0";
}
//c.html
可以看到我们来用的function scope来隔离了两个文件的各自变量不受冲突,但是本身我们用a和b注册了window之上,所以通常会结合下面的方法进一步改进--自执行匿名函数:
常见格式:
(function() { /* code / })();
其他写法:
(function () { / code / } ());
!function () { / code / } ();
~function () { / code / } ();
-function () { / code / } ();
+function () { / code */ } ();
那a.js可以改成下面这样:
var a = (function(){
var version = "1.0.0";
//如果外界要访问,可以return 出去
function say(){
console.log(version);
};
return say;
})();
还有一点,就是当这个自执行函数执行完毕后,比不会从内存销毁高function scope中的所有变量,会形成一个闭包对象.

浙公网安备 33010602011771号