手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜的Vultr , 注册 | 登陆
浏览模式: 标准 | 列表2010年03月16日的文章

Javascript:不要将属性写在prototype里

没有仔细研究过,但觉得得这就象PHP的类(Class)的复制和引用的关系。好象差不多。

原文来自:http://www.beiju123.cn/blog/?p=304

年前,某次分享会上听玉伯偶然说了这句话,当时糊里糊涂,不明所以,偶然有一天我做一个东西,发现某个对象的实例之间竟然会互相操作了定义在 prototype里的属性,于是我验证了下:

JavaScript代码
  1. var objA=function(){  
  2.   
  3. }  
  4. objA.prototype={  
  5.     name:{},  
  6.     setName:function(str){  
  7.         this.name=str;  
  8.     },  
  9.     getName:function(){  
  10.         return this.name;  
  11.     }  
  12. }  
  13. var a=new objA();  
  14.   
  15. var b=new objA();  
  16. //a.name={firstname:"孙",fathername:"信宇"};//undefined  
  17. a.name.firstname="孙";//弹出sun  
  18. alert(b.name.firstname);  

在这个例子里,当我修改实例a的name属性的时候,实例b的name属性页跟着变了,而且说明他们引用了同一份对象.

如果name属性是值类型,例如字符串,就不会与这种问题了,那是因为字符串每次被操作都返回新实例,当然反映不出冲突来了.
那为什么会出现这种冲突呢?
专业术语我不太会讲,但是prototype这种原型继承的好处其实就是节省程序运行空间,当你从objA实例化两个实例:a和b时,并不会创建两份属性 和方法,而是把他们都指向一份属性和方法,所以prototype里的所有的东西都被所有的实例共享,实例中保存的只是一个json索引.
正因为如此,如果整个改变name的值的话,让他指向别的对象,这样就不会互相影响了,而且对于值类型来说,本质就是每次操作都会返回新的实例,所以不会 出现冲突.
对于这种冲突来说,最好的解决办法就是将属性从prototype里移出来,写在构造函数里:

JavaScript代码
  1. var objA=function(){  
  2.     this.name={}  
  3. }  
  4. objA.prototype={  
  5.     setName:function(str){  
  6.         this.name=str;  
  7.     },  
  8.     getName:function(){  
  9.         return this.name;  
  10.     }  
  11. }  

这样再试一次就会发现,每次创建实例都会创建一个新的name属性对象,而不是指向同一个对象;
也可以在prototype理的init方法里用this.name={}来初始化配置参数,属性等内容,反正就是不能写在prototype里面.但是 可以在函数里初始化定义.

还有一点要注意:我个人认为,js里所有的东西都是对象,包括值类型,他们之所以表现出非引用类型的性质,是因为每次对这些对象操作都会返回新的实 例,这只是一种假象,事实上可以说,js里所有的东西都是引用类型,只是值类型在被操作时引用总是被改变,表面上来看就是非引用类型了.

--EOF--

即使是上面的情况,我还是认为可以看看

http://lifesinger.org/blog/2009/01/javascript-run-mechanism/

http://www.cnblogs.com/rainman/archive/2009/04/28/1445687.html