1

每个实例都有一个指向创建它的构造函数原型的链接。所以每个实例都共享原型成员。如果通过一个实例对共享原型成员进行更改,它会反映到所有其他实例。为什么这似乎不适用于原始类型,如下所示:

//creating an empty object type
function OBJTYPE(){};

//adding primitive value and reference value as a memeber to 
//the prototype of the object type
OBJTYPE.prototype.value = 0;
OBJTYPE.prototype.arr = ["red","green","blue"];

//creating instances of the object type
var obj1 = new OBJTYPE();
var obj2 = new OBJTYPE();

//outputting the prototype members through both the instances     
document.write(obj1.value + "<br />");  //0
document.write(obj2.value + "<br />");  //0
document.write(obj1.arr + "<br />");    //red,green,blue
document.write(obj2.arr + "<br />"); //red,green,blue

//changing value of primitive member
obj1.value = 1;  //creates a new instance property

//modifying the reference type member - pushing a value on the array
obj1.arr.push("black"); //modifies the prototype property

//outputting the prototype members through both the instances     
document.write(obj1.value + "<br />"); //1 //.value from instance
document.write(obj1.__proto__.value + "<br />"); //0 //.value from prototype
                                                 //works in Firefox, Safari, and Chrome
document.write(obj2.value + "<br />"); //0 //.value from prototype

document.write(obj1.arr + "<br />");   //red,green,blue,black
document.write(obj2.arr + "<br />");   //red,green,blue,black

正如您在上面看到的,更改原始成员的值会创建一个名为valueon的新实例属性obj1,而不是覆盖原型中相同的命名属性。因此,当访问obj1.value属性时,它会返回掩盖原型属性的实例属性。这就是为什么两个实例实例显示不同的value.

但是,从上面可以看出,这不引用类型的行为并不相似。为什么?

4

4 回答 4

1

当您写入对象中的属性时,新值存储在对象上,而不是原型上。

您遇到的数组问题是这样的:

  1. 获取存储在 obj1 上的数组,并修改数组:obj1.arr.push("black");

  2. 在 obj1 的实例上写入一个新值:obj1.arr = [1,2,3];

如果您需要我,我会扩展。


是的,有很多方法可以做到这一点,具体取决于您的需要。

1 对我来说最明显的是你想要相同的对象,在这种情况下我只会制作一个对象。

var obj1 = {
 "arr": [],
 "value": 0
};
// I can garuntee any editing you do on obj1 will be reflected on obj2
var obj2 = obj1;

2 制作原型访问器方法:

function OBJTYPE(){};

//adding primitive value and reference value as a memeber to 
//the prototype of the object type
OBJTYPE.prototype.value = 0;
OBJTYPE.prototype.arr = ["red","green","blue"];
OBJTYPE.prototype.proto = function (name, optValue) {
 if (arguments.length === 2) {
  return OBJTYPE.prototype[name] = optValue;
 }

 return OBJTYPE.prototype.proto[name];
};

var obj1 = new OBJTYPE();
var obj2 = new OBJTYPE();

obj1.proto('value', 1);  //on the prototype
// The rest will behave like desired

3 存储指向 proto 的直接链接:

function OBJTYPE(){};

//adding primitive value and reference value as a memeber to 
//the prototype of the object type
OBJTYPE.prototype.value = 0;
OBJTYPE.prototype.arr = ["red","green","blue"];
OBJTYPE.prototype.proto = OBJTYPE.prototype;
//creating instances of the object type
var obj1 = new OBJTYPE();
var obj2 = new OBJTYPE();

//changing value of primitive member
obj1.proto.value = 1;  //on the prototype
// The rest will behave like desired

4 最后但同样重要的是,使用 ES5 的方法 getPrototypeOf

function OBJTYPE(){};

OBJTYPE.prototype.value = 0;
OBJTYPE.prototype.arr = ["red","green","blue"];
//creating instances of the object type
var obj1 = new OBJTYPE();
var obj2 = new OBJTYPE();

//changing value of primitive member
Object.getPrototypeOf(obj1).value = 1;  //on the prototype
// The rest will behave like desired
于 2012-10-28T08:23:56.047 回答
1

您正在推送到数组,而不是像使用原始值那样分配新数组。这将按预期工作:

obj1.value = 1; 
obj1.arr = [];

请注意,设置值永远不会在原型上设置,而是在对象本身上设置。

于 2012-10-28T08:24:15.727 回答
0
obj1.value = 1; 

这创建了一个新的属性“值”,obj1并且不会改变原型。这就是为什么obj2.value返回最初在原型中设置的旧值的原因。

如果您想通过改变原型obj1,使其也影响函数的所有其他实例,请通过沿着原型链向下更改属性:

obj1.__proto__ === OBJTYPE.prototype;  //true 
obj1.__proto__.value = 1; 
obj1.value;   //1 
obj2.value;   //1
于 2018-11-05T02:20:34.773 回答
0

我从类似的例子中得出了这个问题:

function Person(first, last, age) {
  this.name = {
    first,
    last
  };
  this.age = age;
};
let person1 = new Person('Tammi', 'Smith', 17); 
let person2 = Object.create(person1);

person2.name.first = "Bob" // modifies prototype value on person1 instance
person2.age = 18           // creates new Property on person2

我相信原因是在 Prototype person1 对象上持有“name”属性的对象被运行时作为关联数组 so 访问person2.name.first = "Bob" is actually person2.name['first'] = "Bob"

当我尝试像这样设置“名称”属性时:

person2.name = "Bob";

first然后在 person2 实例上创建新的属性,有效地隐藏持有属性的person1“名称”对象last。这解释了为什么更改引用实例的内容与设置新的引用实例不同的行为。

于 2021-12-08T21:49:54.937 回答