就在我以为我有JS想出来的时候,我就挂断了这个:
function Obj() {
console.log('x: %s, o.x: %s', this.x++, this.o.x++);
}
Obj.prototype.x = 1;
Obj.prototype.o = {x: 1};
Run Code Online (Sandbox Code Playgroud)
预期:
> new Obj
x: 1, o.x: 1
> new Obj
x: 1, o.x: 1
> new Obj
x: 1, o.x: 1
Run Code Online (Sandbox Code Playgroud)
实际:
> new Obj
x: 1, o.x: 1
> new Obj
x: 1, o.x: 2
> new Obj
x: 1, o.x: 3
Run Code Online (Sandbox Code Playgroud)
因此,似乎如果一个原型属性是一个引用类型,那么它将在所有实例中共享,但如果它是一个非引用类型,那么它将为每个实例重新初始化; 为了证实这个假设,我测试了一些其他类型,例如string(表现得像number)和array(表现得像object).
我确定如果我重新初始化ctor中的object属性,我可以避免这个陷阱,如下所示:
function Obj() {
this.o = {x: 1};
}
Run Code Online (Sandbox Code Playgroud)
这似乎真的非正统(我需要手动重新初始化属性,但只有当它们是参考对象时).
任何人都可以了解正在发生的事情吗?
这样想吧。无论值来自哪里,您总是会修改正在操作的对象。
当您第一次执行此操作时:
this.x++;
Run Code Online (Sandbox Code Playgroud)
x它正在获取from的值Obj.prototype.x,因为该对象上没有x直接的属性this,但++仍在对该对象进行操作this,因此该值是在该对象上设置的。该值现在直接位于实例上以供将来修改。( 一直prototype.x处于阴影状态,直到直接属性为deleted。)
但是,当您这样做时:
this.o.x++
Run Code Online (Sandbox Code Playgroud)
对对象的唯一操作this是查找o。由于 上没有o属性this,您将获得对存储在 上的对象的引用Obj.prototype.o。此时,对象尚未发生实际修改this。
返回引用后,您可以查找对象x的属性Obj.prototype.o并修改它。
所以实际上是非常一致的。您已对this.o.x++执行了查找this,但没有发生突变。突变发生在引用的对象上。但是使用this.x++,您可以直接改变对象。
所以是的,除非您希望在从构造函数创建的所有实例之间共享引用类型,否则您应该将引用类型直接放在实例上,而不是放在.prototype.
| 归档时间: |
|
| 查看次数: |
107 次 |
| 最近记录: |