Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/394.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如果实例本身没有设置属性,那么在更新原型时为什么要更新实例的属性?_Javascript_Prototype - Fatal编程技术网

Javascript 如果实例本身没有设置属性,那么在更新原型时为什么要更新实例的属性?

Javascript 如果实例本身没有设置属性,那么在更新原型时为什么要更新实例的属性?,javascript,prototype,Javascript,Prototype,如果实例本身没有设置属性,那么在更新原型时,为什么要更新存储基元值而不是引用的实例的属性 让我举一个例子: var Obj = function () {}; Obj.prototype.num = 1; var myObj = new Obj(); var myOtherObj = new Obj(); console.log(myObj.num); //logs 1 console.log(myOtherObj.num); //logs 1 //After instances are c

如果实例本身没有设置属性,那么在更新原型时,为什么要更新存储基元值而不是引用的实例的属性

让我举一个例子:

var Obj = function () {};
Obj.prototype.num = 1;

var myObj = new Obj();
var myOtherObj = new Obj();
console.log(myObj.num); //logs 1
console.log(myOtherObj.num); //logs 1

//After instances are created they still share the value (which is strange):
Obj.prototype.num = 3;
console.log(myObj.num); //logs 3
console.log(myOtherObj.num); //logs 3

//Update one of the instances property
myObj.num += 2;
console.log(myObj.num); //logs 5
console.log(myOtherObj.num); //logs 3

//Here it gets weird:
Obj.prototype.num = 4;
console.log(myObj.num); //logs 5 not updated
console.log(myOtherObj.num); //logs 4 updated
这里有几件奇怪的事:

创建实例后,如果且仅当实例本身从未更新过实例值时,更新类定义才会更新实例值

如果我试着解释一下,似乎实例最初没有自己的
num
属性,在原型上发现它的地方会进行查找,但是一旦您实际设置了属性(内部使用
this.num
,外部使用
instanceName.num
)您可以在实例上创建属性

这似乎与ECMA5规范所说的不一致:

prototype属性的值用于在函数对象作为新创建对象的构造函数调用之前初始化新创建对象的[[prototype]]内部属性

听起来它应该填充内部[[Prototype]]实例,但仍然可以通过更新构造函数的Prototype属性来修改它。我知道,如果我将类定义的属性设置为一个对象(如数组),那么引用实际上会传递到实例,并在任何地方更新数组,这将修改每个人的属性,但这些都是原始值,似乎没有多大意义。

其他人会比我更好地解释这一点,所以其他用户,请随意评论我的答案。如果它太离谱,我会删除它


把它想象成继承。如果从构造函数创建的对象没有自己的
num
属性,则它会从其原型(或父对象、超级对象或其他对象)中查找值

所以不管这个值是什么,都是你得到的值。更新它,任何查看它的对象都会找到更新的值

我相信原型属性不是为每个实例复制的,而是由实例“查找”的。因此,原型属性的值实际上不会增加对象的大小,因为所有属性共享同一个集合


编辑:这可能也有帮助。第5版规范定义下的第4.3.4节和第4.3.5节

4.3.4

构造函数

创建和初始化对象的函数对象。 请注意,构造函数的“prototype”属性的值是用于实现继承和共享属性的prototype对象

4.3.5

原型

对象,该对象为其他对象提供共享属性

注意:当构造函数创建对象时,该对象隐式引用构造函数的“原型”属性以解析属性引用。构造函数的“prototype”属性可以被程序表达式constructor.prototype引用,并且添加到对象原型的属性通过继承被共享原型的所有对象共享。或者,可以使用object.create内置函数使用显式指定的原型创建新对象


其工作方式是首先在对象上查找属性,如果没有找到,则在原型中查找属性

如果我试图解释它,它 看起来像是一开始的例子 没有自己的num属性和 查找发生在发现它的地方 在原型上,但是一旦你 实际设置属性(内部) 使用this.num或外部使用 (instanceName.num)创建一个 实例上的属性。实例上的属性

这就是它的工作原理。如果要删除在对象上设置的属性,可以使用“删除”:

delete myOtherObj.num;
这将删除myOtherObj的num属性,并允许原型版本显示出来

您引用的规范部分试图解释如何为新创建的实例设置内部[[Prototype]]属性。除了在属性查找中的角色,[[Prototype]]与其他Javascript对象引用类似

因此,当构造函数的“prototype”属性被“复制”到新创建的对象的[[prototype]]中时,它实际上获得了对构造函数上原始prototype属性的引用,以后可以修改


另一个例子是:

function Obj() {};
Obj.prototype.num=1;

var myObj = new Obj();
console.log(myObj.num); // logs 1

Obj.prototype = {num:3}; // replaces Obj.prototype
console.log(myObj.num); // logs 1

var myOtherObj = new Obj(); 
console.log(myOtherObj.num); // logs 3
console.log(myObj.num); // still logs 1

请注意,一旦构建了对象,它将保留对在调用构造函数时设置为构造函数原型的任何对象的引用。更改该对象的属性仍将影响对同一原型的任何其他引用。

这是完全正常的,而不是奇怪的。;)

当您试图访问一个对象的属性时,该属性没有在该对象中设置,JS引擎将获取原型链并尝试在那里读取它。只要未在该对象中显式设置该属性,则这是正确的

当您更改对象继承的类的原型时,对象本身的属性不会更改,只是仍然没有设置,并且仍然读取该类的属性

只有在设置对象的某个特性时,该特性才在该对象中定义。这也是当您更改对象的原型时,已声明对象的特定属性发生更改的原因

澄清:

Obj.prototype.num = 3;
console.log(myObj.num); //logs 3
console.log(myOtherObj.num); //logs 3
在这里,您实际上仍然在阅读
Obj.prototype.num

myObj.num += 2;
Obj.prototype.num = 4;
console.log(myObj.num); //logs 5 not updated
console.log(myOtherObj.num); //logs 4 updated
在这里,您实际上阅读了
Obj.prototype.num
,并将其写入
myObj.num

myObj.num += 2;
Obj.prototype.num = 4;
console.log(myObj.num); //logs 5 not updated
console.log(myOtherObj.num); //logs 4 updated

现在您分别阅读了
myObj.num
Obj.prototype.num

Aha。这是有道理的。谢谢