原型在这里发生了什么

时间:2013-06-10 07:19:47

标签: javascript prototype

所以我有以下内容:

function A () { this.a = 0; }
function B () { this.b = 0; }
function C () {}

C.prototype = new B();

var c1 = new C();
var c2 = new C();

c1.b = 10;

console.log(c1.b); // 10 
console.log(c2.b); // 0

http://jsfiddle.net/Mars6/2/

当我将B.b更改为某个对象时,它似乎为每个新C存储了相同的对象:

function A () { this.a = 0; }
function B () { this.b = new A(); }
function C () {}

C.prototype = new B();

var c1 = new C();
var c2 = new C();

c1.b.a = 10;

console.log(c1.b.a); // 10 
console.log(c2.b.a); // 10 - I want this to be 0

http://jsfiddle.net/Mars6/1/

任何人都可以解释发生了什么/问题是什么。

2 个答案:

答案 0 :(得分:6)

当你做了

C.prototype = new B();

您没有说“无论何时需要原型,请new B”。你所说的是“将原型分配给new B()(这不应该是非常令人惊讶的。)你得到的是:

C.prototype.b.a === 0

每当您执行new C时,您都不会重复C.prototype - 您只是链接到它B objcet:

C.prototype = new B()
   ^    ^
   |    |
  c1    c2

c1.b === c2.b; //true

您可能知道,对象可以根据您的内容进行更改。因此,当你执行c1.b.a = 4时,你将进入基础对象并乱用它。

编辑:第一个示例有效,因为属性解析的工作原理。 b属性不驻留在对象c1c2上。当你说“给我c1.b”时,js引擎就是这样的:

  1. b上有c1个属性吗?不,没有。
  2. 让我们看一下c1的原型(实际原型,对象得到的方法和属性 - 在本例中为C.prototype
  3. 哦,是的,它有一个b属性。归还。
  4. 在实际的js中,这是(spec):

    function GetProperty (name, obj) {
        while (obj !== null) {
            if (obj.hasOwnProperty(name)) {
                return obj[name];
            }
            obj = Object.getPrototypeOf(obj);
        }
        return undefined;
    }
    

    因此,在b是一个对象的情况下,你拥有一个对象。更改它会像普通对象一样改变它(注意你没有直接分配给c1.b - 你会看到我的意思)。用箭头解释:

    C.prototype.b = 0
       ^     ^
       |     |
      c1.b   c2.b
    

    这很重要,所以我再次强调一下:当你抓住c1.b时,你会得到一个被操纵的物体,就像任何其他物体一样。为它分配属性就像任何其他普通对象一样,并将其改变......好吧,改变它。

    现在,在前一种情况下(c1.b = 10),您实际上是分配属性。这意味着您要在c1对象本身上创建键/值配对。因此,在第一步中,我们会查看c1是否具有属性b - 并且它具有。用更多箭头解释:

          C.prototype.b = 0
                ^
                |
      c1.b=10  c2.b
    

    改变后一个例子,我们可以观察到相同的效果:

    //changing
    c1.b.a = 10;
    //to
    c1.b = 4;
    
    c2.b !== 4 && c2.b.a === 0; //true
    

    回顾一下:

    • 在前一个示例中,您只需在c1对象上设置属性。
    • 在后一个示例中,您在c1原型上的对象上设置了一个属性,该对象在所有其他C个对象上进行了变异。

答案 1 :(得分:3)

据我所知,这是最新发生的事情:

function A () { this.a = 0; }
function B () { this.b = 0; }
function C () {}

C.prototype = new B();

var c1 = new C();
var c2 = new C();

c1.b = 10;

当您编写c1.b = 10时,JavaSript将只添加或更改对象b的本地属性c1。它并不关心原型是否已经具有属性b,在这种情况下它仍然完全不受影响。因此:

console.log(c1.b); // 10  --> local property in c1
console.log(c2.b); // 0   --> prototype property

在你的第二个例子中,你正在做一些不同的事情。您没有将属性分配给c1,而是操纵它的原型,从而影响所有实例:

c1.b.a = 10;

c1没有属性b,因此它将从原型对象中获取并添加或更改ITS属性a。现在c1c2都没有获得本地属性,因此都引用了更改的原型:

console.log(c1.b.a); // 10  --> points to the prototype
console.log(c2.b.a); // 10 --> points to the prototype

可能的解决方案

c1.b = new A();
c1.b.a = 10