?
?? ? ?除了模拟类的私有变量和私有方法。闭包还可用来模拟类的静态变量和方法。
?
除了再次利用js的闭包特性,还需要借助js语法上的一些特点。看下面一段代码:
?
?
var MyNamespace = {}; // 定义命名空间 MyNamespace.TreeItem = (function(){ //使用闭包产生的私有静态变量,不可被外部访问 var numTreeItems = 0; //使用闭包产生的私有静态方法,不可被外部访问 function counter(){ numTreeItems ++; console.log("Created "+numTreeItems+" tree items!"); } //该匿名函数的引用将被赋予MyNamespace.TreeItem return function(){ //使用闭包产生的私有类变量,不可被外部访问 var label; //可访问私有变量,也可被外部访问的方法 this.setLabel = function( newLabel ){ label = newLabel; }; this.getLabel = function(){ return label; }; //该方法用来累计实例的数量 counter(); } })(); //在函数定义的末尾加上括号,表示该函数在定义后立即执行 //不可访问私有变量以及其它公共方法的静态公共方法 MyNamespace.TreeItem.clone = function(otherInstance){ }; MyNamespace.TreeItem.prototype = { // 不可访问私有变量,但可访问其它公共方法的公共方法 print: function(){ console.log(this.getLabel()); } }; var treeItem1 = new MyNamespace.TreeItem(); // print 1 var treeItem2 = new MyNamespace.TreeItem(); // print 2?
?
?
执行上述代码后,浏览器控制台将会输出如下字符串:
?
?Created 1 tree items!
?Created 2 tree items!
?
之所以把上述一些js变量和函数称为“静态”,是借用了Java的提法。
?
这些“静态”变量和方法被保存在闭包中,在内存中是唯一的,
?
不会随着该函数副本的增加而增加。如果一个函数需要被实例化多次,
?
但其中的一些内部函数并不需要访问任何实例数据,从节省内存的角度考虑,
?
可采用上述构建静态函数的方法。js中的“静态”概念,有一点与Java不同:
?
如果上述TreeItem被设为null,即不再有引用指向它,那么它的闭包也将消失,
?
保存在闭包中的静态变量和方法,也将被垃圾回收器择机回收。
?
?
1 楼
bigbighead
2010-11-18
哦,又学了一招
2 楼
bigbighead
2010-11-18
请教博主一个问题:
从您文章中,我发现您提到的静态成员是私有的(外界不可访问)
使用JavaScript 闭包,是否可以定义 外界可访问的 成员呢?
从您文章中,我发现您提到的静态成员是私有的(外界不可访问)
使用JavaScript 闭包,是否可以定义 外界可访问的 成员呢?
3 楼
hbc8848
2010-11-18
bigbighead 写道
请教博主一个问题:
从您文章中,我发现您提到的静态成员是私有的(外界不可访问)
使用JavaScript 闭包,是否可以定义 外界可访问的 成员呢?
从您文章中,我发现您提到的静态成员是私有的(外界不可访问)
使用JavaScript 闭包,是否可以定义 外界可访问的 成员呢?
外界如果想访问闭包中的变量,唯一的途径是通过定义一个getXXX()取值器方法.
在上例第15行开始的那个函数中,我们定义一个 getNumTreeItems(){ return numTreeItems;}
方法,外界就可以取到静态私有变量numTreeItems了,这样凡是能拿到TreeItem任意一个实例的对象都会知道一共有几个TreeItem的实例被创建出来。
4 楼
biyelei
2011-01-13
5 楼
sdtm1016
2011-05-24
请教博主一个问题:
匿名闭包,在内存中是唯一的(是否是因为关联了匿名对象呢?),和非匿名闭包,不是唯一,具体的区别在哪里呢?
谢谢
var MyNamespace = {}; MyNamespace.TreeItem = (function() { var numTreeItems = 0; function counter() { numTreeItems ++; console.log("Created "+numTreeItems+" tree items!"); //alert(numTreeItems); } return counter; })(); var treeItem1 = new MyNamespace.TreeItem(); var treeItem2 = new MyNamespace.TreeItem(); var treeItem3 = MyNamespace.TreeItem(); var treeItem4 = MyNamespace.TreeItem();
匿名闭包,在内存中是唯一的(是否是因为关联了匿名对象呢?),和非匿名闭包,不是唯一,具体的区别在哪里呢?
谢谢
6 楼
sdtm1016
2011-05-24
http://www.iteye.com/problems/65721
看了他的提问,没想明白
看了他的提问,没想明白
7 楼
HeroCL
2011-05-24
sdtm1016 写道
http://www.iteye.com/problems/65721
看了他的提问,没想明白
看了他的提问,没想明白
这个问题我考虑了一个礼拜了,就是没有弄明白,匿名闭包里的变量为什么只有一份,斑竹给个答案啊!!!!
8 楼
hbc8848
2011-05-25
sdtm1016 写道
请教博主一个问题:
匿名闭包,在内存中是唯一的(是否是因为关联了匿名对象呢?),和非匿名闭包,不是唯一,具体的区别在哪里呢?
谢谢
var MyNamespace = {}; MyNamespace.TreeItem = (function() { var numTreeItems = 0; function counter() { numTreeItems ++; console.log("Created "+numTreeItems+" tree items!"); //alert(numTreeItems); } return counter; })(); var treeItem1 = new MyNamespace.TreeItem(); var treeItem2 = new MyNamespace.TreeItem(); var treeItem3 = MyNamespace.TreeItem(); var treeItem4 = MyNamespace.TreeItem();
匿名闭包,在内存中是唯一的(是否是因为关联了匿名对象呢?),和非匿名闭包,不是唯一,具体的区别在哪里呢?
谢谢
我看了 http://www.iteye.com/problems/65721
这个问题和匿名函数并没有关系,二者的区别实际在代码的31行:
})(); //在函数定义的末尾加上括号,表示该函数在定义后立即执行
我的文章二里定义闭包的函数共计运行了两次,而该篇文章三的定义闭包函数只在31行处运行了一次。定义闭包的函数每运行一次,都会在内存中新建一个新的“类静态私有变量”。 之所以使用匿名函数构造闭包,就是为了模拟java里的类定义仅能定义一次,不希望用户使用命名函数来多次定义我们的js“类”。毕竟js和java相比有太多不同。
9 楼
sdtm1016
2011-05-25
这回明白了
10 楼
hbc8848
2011-05-25
HeroCL 写道
sdtm1016 写道
http://www.iteye.com/problems/65721
看了他的提问,没想明白
看了他的提问,没想明白
这个问题我考虑了一个礼拜了,就是没有弄明白,匿名闭包里的变量为什么只有一份,斑竹给个答案啊!!!!
这个问题和js的解释机制有关,因为js是函数式解释语言,一个函数里引用到的所有变量都会被保存而不会被垃圾回收器回收,也就是说函数在被定义时赖以运行的上下文环境会被js解释器原样封存起来,直到函数被再次调用时,再从内存中取出那些所谓的“静态变量”来影响函数的运行结果。这也是我们称之为闭包(closure)的来由。这些被引用到的“静态变量”并不会随着new出来的函数实例的增多而增多,它们在内存中永远只有一份。如果我们把js中的new一个函数比作java里的clone方法的话,那么我们要说js的clone同样是浅拷贝而不是深拷贝,即只拷贝基本类型而不拷贝引用。我想这么说可以更好地帮助我们理解“闭包”。