通过更改构造函数属性动态替换原型。

3

我想编写一些代码示例来体验JavaScript的“非类”特性。到目前为止,我已经想出了以下内容:

function One() {}
function Two() {}

One.prototype.a = 5;
Two.prototype.b = 4;

var obj = new One();
print("1) ctor =", obj.constructor, "a =", obj.a, " b =", obj.b);
obj.constructor = Two;
print("1) ctor =", obj.constructor, "a =", obj.a, " b =", obj.b);

var objTwo = new obj.constructor();
print("2) ctor =", objTwo.constructor, "a =", objTwo.a, " b =", objTwo.b);

以下是相应的打印信息:

1) ctor = function One() {
} a = 5  b = undefined
1) ctor = function Two() {
} a = 5  b = undefined
2) ctor = function Two() {
} a = undefined  b = 4

我的问题是为什么原型链在这里不按照书本上的方式工作?我在使用JavaScript(spidermonkey)(spidermonkey-1.7)在ideone上运行我的示例。看起来在实际生活中,原型是以某种其他方式访问的,而不是通过constructor.prototype访问?
P.S. 进一步的实验表明,对obj.constructor进行赋值会添加新属性,这会遮盖原始属性。为什么?..

1
每个实例的 constructor 属性在内部没有任何作用。 - Felix Kling
3个回答

1
是的,有Object.__proto__和直接的Object.prototype。如果您打印One.prototype,您应该会看到所需的结果。如果您执行console.dir(someInstance);,则会在someInstance的下方直接列出实例变量。
之后,您可以展开prototype,然后您将看到为该原型定义的方法(例如,One.prototype.doSomething=function(a){})。
了解更多关于Object.__proto__的信息HERE以及关于Object.prototype(标准)的信息HERE

1

最初,你的var obj没有名为constructor的属性。当你打印它时,它通过其原型(One.prototype)解析——所有原型都有一个构造函数。当你分配obj.constructor = Two时,你在obj中创建了一个自有属性,它遮盖了原型属性。这个新属性对引擎来说毫无意义,也不会以任何方式影响继承。

总的来说,“constructor”似乎是一个纯信息性的属性,没有任何特定的用途。它只是一个从函数原型返回到父函数的反向链接。请参见创建函数构造函数以获取更多参考资料。


谢谢,非常合乎逻辑的解释。console.log(One.prototype.hasOwnProperty("constructor")); 输出 true - Roman Saveljev

0
问题在于你进入了具体的细节,然后开始乱动线缆。这里并没有按照规范的步骤进行,因为你插入了这个指针,打乱了自然的顺序。
obj.constructor = Two;

那不是正确的继承方式。这才是:

function One() {}
function Two() {}

One.prototype.a = 5;
Two.prototype = new One();
Two.prototype.b = 4;

现在,使用new Two()实例化的任何对象都将在构造函数中正确显示is-a关系(继承)。这里有一个jsFiddle演示展示了差异。


嗯,我只是假设原型是通过构造函数属性解析的。正如alex23所描述的那样,我的假设是错误的。这就是我想澄清的全部内容。感谢您花时间写答案。 - Roman Saveljev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接