【问题标题】:why is a.y undefined here?为什么 a.y 在这里未定义?
【发布时间】:2015-05-24 20:58:53
【问题描述】:
function A() {}
A.prototype.x = 10;

var a = new A();
alert(a.x); // 10

A.prototype = {
  x: 20,
  y: 30
};

alert(a.y) // undefined
  1. 为什么它委托给old prototype of a.x而不是新的 一个?
  2. 为什么a.y会通过undefined投掷prototype

【问题讨论】:

  • 因为a 是从旧原型创建的。它链接到原型对象,而不是A,因此分配不会改变任何东西。另见herethere

标签: javascript inheritance prototype


【解决方案1】:

这是因为你设置了A.prototype = obj

您没有向a 继承的Object 添加属性,而是创建了一个全新的对象A.prototype,而这个对象并没有被a 继承

考虑一下,

function A() {}
A.prototype.x = 10;

var p1 = A.prototype; // keep reference to this

var a = new A();

A.prototype = {x: 20, y: 30};

Object.getPrototypeOf(a) === A.prototype; // false, not the new prototype
Object.getPrototypeOf(a) === p1; // true, the old prototype

// however
var b = new A();
Object.getPrototypeOf(b) === A.prototype; // true, this is the new prototype

如果您对旧原型(我称之为p1)的属性进行了更改,那么这些属性将被a 继承

【讨论】:

  • 不是我们不能改变... proto引用了旧的原型,通过它我们可以改变它来引用新的原型。
  • @Thalaivar 使用obj.__proto__ 不是一个好习惯,而且使用Object.setPrototypeOf 的成本非常高,如果您预计需要做这些事情,要么从更长的原型开始链与一个空的,你可以修改,或分离你的代码使用多个构造函数。
  • 您的答案清晰明了,但是正如您所知,在 JavaScript 中没有死锁情况,总有一种解决方法,尽管有时像您提到的那样代价高昂。干杯:)
【解决方案2】:

为什么它委托给旧的 a.x 原型而不是新的原型? 为什么 a.y throwing undefined 是在原型中设置的?

您已经创建了一个完整的new prototype object。在原型属性更改之前已经创建的对象将具有旧的引用,而新的 objects 将具有新的 prototype

// was before changing of A.prototype
a.[[Prototype]] ----> Prototype <---- A.prototype

// became after
A.prototype ----> New prototype // new objects will have this prototype
a.[[Prototype]] ----> Prototype // it will still reference to old prototype

经验法则是,prototype 是在对象创建的时刻设置的,以后不能更改。只能添加新的或修改object’s prototype 的现有属性。

但是,您可以使用__proto__ 属性来解决问题。

function A() {}
A.prototype.x = 10;

var a = new A();
alert(a.x); // 10

var _newPrototype = {
  x: 20,
  y: 30
};
A.prototype = _newPrototype; //will fail
alert(a.y) // undefined

A.__proto__ = _newPrototype; //will work
alert(a.x);
alert(a.y);

【讨论】:

    【解决方案3】:

    您刚刚为类“A”创建了一个新的原型对象,即 A

    的旧实例
    var a = new A();
    

    ...确实为它的实例复制了现有的原型对象reference。旧的原型对象是它自己的对象,它不会被销毁,因为“A”的实例持有该引用。

    如果要定义“y”,则必须使用 new 再次创建 object,新实例将使用您为原型分配的对象- 该实例定义了“y”。

    http://jsfiddle.net/ejseLum9/

    【讨论】:

    • ...除了原型没有被复制,它们被引用。
    • 谢谢!是的,只少了一个小字:-)
    猜你喜欢
    • 1970-01-01
    • 2018-07-09
    • 1970-01-01
    • 2021-11-09
    • 2010-11-27
    • 1970-01-01
    • 2011-05-05
    • 2014-04-11
    相关资源
    最近更新 更多