原型类型在原型中的行为

时间:2012-10-28 08:17:25

标签: javascript prototype prototype-chain

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

//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

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

然而,从上面可以看出,这种不参考类型的行为不同。为什么呢?

3 个答案:

答案 0 :(得分:1)

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

你有这样的数组问题:

  1. 获取存储在obj1上的数组,并修改数组: obj1.arr.push( “黑色”);

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

  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
    

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:0)

obj1.value = 1; 

这创建了obj1的新属性“值”,并且没有使原型变异。这就是obj2.value返回与原型中最初设置相同的旧值的原因。

如果您想通过obj1修改原型,以使其也影响该函数的所有其他实例,请通过沿着原型链进行更改来更改属性:

obj1.__proto__ === OBJTYPE.prototype;  //true 
obj1.__proto__.value = 1; 
obj1.value;   //1 
obj2.value;   //1