什么';这是JavaScript';s对象。原型行为?
我遇到了一段奇怪的代码片段,我完全无法理解,它是:什么';这是JavaScript';s对象。原型行为?,javascript,object,prototype,javascript-objects,Javascript,Object,Prototype,Javascript Objects,我遇到了一段奇怪的代码片段,我完全无法理解,它是: var obj = function() {}; obj.prototype.x = 5; var instance1 = new obj(); obj.prototype = {y: 6}; var instance2 = new obj(); console.log(instance1.x, instance1.y, instance2.x, instance2.y); // 5, undefined, undefined, 6
var obj = function() {};
obj.prototype.x = 5;
var instance1 = new obj();
obj.prototype = {y: 6};
var instance2 = new obj();
console.log(instance1.x, instance1.y, instance2.x, instance2.y);
// 5, undefined, undefined, 6
现在,问题是:
5,未定义,未定义,6
,而不是未定义,6,未定义,6
感谢您的每一个解释。原型是一项与新的幕后功能相结合的功能。它适用于与new一起使用的该函数的所有实例。在第一个示例中,您将.x=5追加到原型中,并且您创建的实例的值为.x=5。稍后将原型修改为新对象。现在,这就是任何新实例中使用的原型。这就是为什么第一个实例只有.x=5,第二个实例只有.y=6的原因 因此,首先,您的两行代码创建一个函数,
obj
,并分配给它的原型{x:5}
当您创建此对象的实例时,它似乎有一个内部引用,指向当它是new
'd时存在的原型
在此之后,将原型重新分配给{y:6}
,这不会影响对第一个原型的实例1
内部引用
然后,当您创建instance2
时,它具有对第二个原型的内部引用,因此,记录它们将生成5,未定义,未定义,6
#4
您可以,而不是将原型重新指定给新对象:
obj.prototype = {y: 6};
改为修改原型:
delete obj.prototype.x; // Setting to undefined should produce same behaviour
obj.prototype.y = 6;
这将产生输出:undefined,6,undefined,6
我已经在Windows上的Chrome和Firefox最新版本上对此进行了测试。因为已经创建了
实例1
。new
关键字通过执行构造函数创建新对象,在您的例子中,构造函数是obj
因为您在第一个实例初始化后更改了原型,所以您不再具有相同的构造函数状态(例如原型),并且无法生成相同的对象。但创建的模型仍然存在,参考了旧的原型
当您再次使用obj
构造函数时,您正在创建另一个对象,该对象可以非常粗略地转换为经典类型的继承术语,作为另一个类的实例
编辑:#4
这把小提琴:
表明
obj.prototype.y=6
成功更改所有现有对象。因此,答案显然是不应该将新对象指定为原型,而应该修改当前原型。实例的原型不引用类,而是引用原型对象本身。当您尝试
Object.getPrototypeOf()
查看实例引用的原型对象时,这一点就会变得很清楚
Object.getPrototypeOf(instance1)
Object { x: 5, 1 more… }
Object.getPrototypeOf(instance2)
Object { y: 6 }
该字段getPrototypeOf
references应该是每个实例都存在的内部字段。在getPrototypeOf
存在之前,您可以根据
prototype
属性的值用于初始化新创建对象的[[prototype]]
内部属性,然后将函数对象作为新创建对象的构造函数调用
很明显,prototype
只是初始化[[prototype]]
属性。当我们创建一个对象时,[[Prototype]]
被设置为构造函数的Prototype
对象,并建立原型链。在你的情况下,当你
var obj = function() {};
obj.prototype.x = 5;
var instance1 = new obj();
[[Prototype]]
如下所示
console.log(Object.getPrototypeOf(instance1));
# { x: 5 }
Object.setPrototypeOf(instance1, {
y: 6
});
delete obj.prototype.x;
obj.prototype.y = 6;
console.log(Object.getPrototypeOf(instance1) === Object.getPrototypeOf(instance2));
# true
console.log(Object.getPrototypeOf(instance1) === obj.prototype);
# true
(是的,您可以使用对象.getPrototypeOf
函数访问[[Prototype]]]
)
因此,当JS引擎在instance1
中查找x
时,它发现值为5
,并且由于y
未定义,因此它使用未定义的
在第二种情况下
obj.prototype = {y: 6};
var instance2 = new obj();
您正在更改obj
的prototype
对象,以便使用此函数构造的新对象将使用分配给它的新对象。因此,[[Prototype]]
对于instance2
console.log(Object.getPrototypeOf(instance2));
# { y: 6 }
这就是为什么,instance2
无法在其中找到x
,而y
要回答最新的问题
编辑:我如何更改所有实例的原型
您可以使用object.setPrototypeOf
更改旧对象的原型,如下所示
console.log(Object.getPrototypeOf(instance1));
# { x: 5 }
Object.setPrototypeOf(instance1, {
y: 6
});
delete obj.prototype.x;
obj.prototype.y = 6;
console.log(Object.getPrototypeOf(instance1) === Object.getPrototypeOf(instance2));
# true
console.log(Object.getPrototypeOf(instance1) === obj.prototype);
# true
因为这使得instance1
的[[Prototype]]
与instance2
不同,所以我们只需更新构造函数的Prototype
对象,如下所示
console.log(Object.getPrototypeOf(instance1));
# { x: 5 }
Object.setPrototypeOf(instance1, {
y: 6
});
delete obj.prototype.x;
obj.prototype.y = 6;
console.log(Object.getPrototypeOf(instance1) === Object.getPrototypeOf(instance2));
# true
console.log(Object.getPrototypeOf(instance1) === obj.prototype);
# true
现在,我们没有更改instance1
和instance2
的内部属性。我们可以这样检查
console.log(Object.getPrototypeOf(instance1));
# { x: 5 }
Object.setPrototypeOf(instance1, {
y: 6
});
delete obj.prototype.x;
obj.prototype.y = 6;
console.log(Object.getPrototypeOf(instance1) === Object.getPrototypeOf(instance2));
# true
console.log(Object.getPrototypeOf(instance1) === obj.prototype);
# true
注意:惯例是将构造函数的首字母命名为大写字母
为什么此日志记录为5
,未定义
,未定义
,6
而不是未定义
,未定义
,6
为什么替换原型并不像通常那样更改对象所有实例的原型
从根本上说,这归结为一个事实,即对象引用是值,而不是数字,它告诉JavaScript引擎(在您的例子中是V8)对象在内存中的位置。复制值时,您只需执行以下操作:复制值。复制对象引用将生成t的副本