当前位置:编程学习 > JAVA >>

javascript 原型继承的问题

a1的原型属性c是个数组[1,2,3] a2继承了a1 重新为a2的原型属性c赋值为[5] a1的c数组还是[1,2,3]?没有发生改变?原型属性难道没有共享? var a1 = function(){ } a1.prototype.c = [1,2,3]; var a2 = function(){ } a2.prototype = new a1(); var p2 = new a2(); p2.c=[5]; alert(p2.c); var p1 = new a1(); alert(p1.c);
追问:把p2.c = 5 修改为 p2.c.push(5)


p1.c属性变为1,2,3,5
p2.c属性也是1,2,3,5
影响了原型。。。为什么?
答案:shy2850回答的没问题
补充一点
Javascript中p2.c这种形式的取值,首先在p2这个对象中寻找是否有c这个属性,如果有直接返回c的值,如果没有的话,回到p2这个类的原型对象里面去找c的属性,找到则返回,找不到会报错.

所以你的追问中:为什么把p2.c = 5 修改为 p2.c.push(5)就可以的原因:
p2.c = 5是一个赋值操作,相当于在对象p2中添加一个c属性.
p2.c.push(5)先是在p2对象中查找c属性,没有查到,则返回原型对象的c属性,然后调用原型对象c的push方法,将5加入的原型对象的数组中
其他:原型的意思就是提供一个default模板,只是在new 对象的时候提供占位的对象,如果你更改了对象的属性也不可能影响到原型的。

var p2 = new a2();
p2.c=[5];

这个不等同于:
var p2 = new a2();
a2.prototype.c=[5]; 当引用对象的某个属性时,js先检测对象属性中是否有这个成员,如果没有,则检查原型链上是否有这个属性,如果也没有,则返回undefined。
然而当对象属性作为左值时(比如赋值号的左边),并没有以上的这种检测机制,因为js的对象是动态的,用对象的某个属性作为赋值的接收器,相当于先给这个对象注册该属性(假设原来没有这个属性),然后赋值,即使该对象没有这个属性成员,赋值也是合法的。

p2.c=[5]; 

这一句是不检测p2原型链上是否有c这个属性的,而是直接给p2这个对象注册了c属性,从而c成为p2的对象属性,隐藏了p2的原型属性c。p2从原型a1中继承而来的c还是不变的,只是被对象属性给隐藏了,通过p2已经不可获得了。当然,如果使用的是非IE浏览器,p2对象还是可以获得原型属性c的,你可以弹出p2.__proto__.c看看,它依然是[1,2,3],而p2.c就是[5],这个 __proto__(双下划线proto)里保存着从原型继承而来的属性,是webkit浏览器实现prototype的一种解决方法。
把

p2.c=[5]; 改成: p2.__proto__.c=[5];

就可以看到你预期的效果了。(非IE下可以,因为IE目前还没有暴露对象的__proto__成员,所以无法实现)

总结一句,对象属性取值和对象属性赋值是不一样的,前者检测原型链,后者单纯的注册属性给对象。 原型的意思就是提供一个default模板,只是在new 对象的时候提供占位的对象,如果你更改了对象的属性也不可能影响到原型的。这句话是对的。但是,如果你修改了原型的属性,那么有可能影响到对象。
       在访问对象属性的时候,如果当前对象拥有该属性的话,则不会用到原型属性;如果没有的话,会沿着原型链一直往上找,直到找到为止,否则返回undefined。在给对象属性赋值的时候,不管对象有没有该属性,都不会用到原型属性。有的话,直接赋值;没有的话,给对象增加一个属性,然后再赋值,并且这个属性是该对象独有的。(例如上面p2.c=5,和p1.c是不一样的)
       接上面的例子:

       p2.a=5;//赋值
       alert(p1.a);//undefined

       当改为:
       p2.c.push(5)//这里不是赋值,而是修改了原型属性。p2.c指向的是原型属性数组c,而数组的push方法是在原数组上操作,它并不会产生一个新的数组,又因为原型属性是共享的,所以p1会受到影响。

上一个:spring与hibernate的事务有什么区别?
下一个:java的父类static疑问

CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,