var a=function(){
//empty
}
a.prototype.var1=[1,2,3];
var b=new a();
b.var1.push(4);
var c=new a();
alert(c.var1.join(","))
最后输出的是1,2,3,4 非常不解?
给实例b push的4,
为什么实例c 会输出4 ,又不是b.prototype.var1.push(4);
话说为什么改成b.prototype.var1.push(4);
会爆一个Uncaught TypeError: Cannot read property 'var1' of undefined(…)
var a=function(){
//empty
}
a.prototype.var1=[1,2,3];
var b=new a();
b.var1.push(4);
console.log(b.__proto__.var1)
var c=new a();
console.log(b.__proto__.var1 === c.__proto__.var1)
console.log(b.__proto__.var1 === a.prototype.var1)
var b=new a() 所以 b.__proto__指向a.prototype
你直接b.var1会先找b上面有没有var1变量,再找a.prototype上面有没有这个变量,由于指向同一个变量,所以b和c改了会相互影响。
我觉得,小b是实例a出来的,所有b.var1的时候,就通过原型查找到了在小a原型上的var1这个数组,他们是同一个堆内存,内存地址在一样的,等于是(小a和小b是指向的同一个命名空间的内存地址),那么再实例化一个小c,同样也指向了这个内存地址,所以小c.var1也通过原型链查找到了var1这个空间,join以一个逗号分割每一项。 你后面的问题,b.prototype.var1.push(4);在小b的原型上是没有var1这个属性名的,所以会报错,说不能读取到var1,是没定义的! 希望能对你有帮助!
第一个问题,因为b
实例(也就是new a()
,也可以说是a
的实例)上并没有var1
属性,b.var1
在b
上找不到var1
这个属性,就去b
的父原型——a.prototype
上找,找到了,因此b.var1
实质上是指向a.prototype.var1
。你在b.var1
作修改对象的操作(如数组的push
或者添加、删除属性)都是直接操作在a.prototype
;
第二个问题,.prototype
是函数上的属性(这里特指构造函数),实例上是没有prototype
属性的;如果要在b
的父原型上进行操作,应该:
a.prototype.var1.push(4)
// 或者
b.__proto__.var1.push(4)
但这样都会影响到a
的新实例(也就是c
),如果想每个实例都有自己的var1
数组,可以:
// 在构造函数内指定,覆盖父原型上的属性
var a = function() {
this.var1 = [1, 2, 3]
}
// 或者重新给实例复制一个数组
b.var1 = b.var1.slice()
a应该写成A,表明它是一个'类',A.prototype.var1 = [1,2,3]中,var1是个类变量
实例修改了类变量,必然会影响到其他的实例
如果所示,b 和 c 都是通过 构造函数 a new 出来的实例。
LZ可以看看我的这篇文章https://.com/a/1190000003017751
因为他们在内存中都是指向同一个prototype,目的是减少内存开销
prototype只是a构造函数的属性,你b.prototype是错的,为什么c输出4原因是原型对象特点就是共享,所以你修改了b,在c上也会体现。你可以看看《js高级程序设计》第158页的原型对象问题那一块,例子差不多的
b.prototype.var1.push(4);会报错是因为b是类a实例化后的一个对象,b并不是一个构造函数,此时b并没有显式的prototype属性