为什么在JavaScript中列出类的实际构造函数很重要?

8
我在阅读 JavaScript Garden http://bonsaiden.github.com/JavaScript-Garden/ 时了解到了 JavaScript 中的原型,其中有一个示例如下:
function Foo() {
    this.value = 42;
}
Foo.prototype = {
    method: function() {}
};

function Bar() {}

// Set Bar's prototype to a new instance of Foo
Bar.prototype = new Foo();
Bar.prototype.foo = 'Hello World';

// Make sure to list Bar as the actual constructor <-------------------
Bar.prototype.constructor = Bar;

请注意阅读这行代码:确保将 Bar 作为实际构造函数列出。我真的不知道这是做什么/是什么。我尝试过使用和不使用最后一行来创建 Bar() 的新实例。但是在这些实例上调用"value"或"method"返回完全相同的结果。所以我想知道,指定构造函数的必要性是什么(我认为肯定有一个)。谢谢!
2个回答

6
每个函数都有一个“prototype”属性,该属性在函数对象创建时分配,它指向一个新创建的对象,该对象继承自“Object.prototype”,并且它具有一个“constructor”属性,该属性简单地指向函数本身。
“prototype”属性的目的是提供一种使用构造函数实现继承的方式。当您使用“new”运算符调用函数时,它将创建一个新对象,该对象继承自该构造函数的“prototype”。
现在,“constructor”属性的目的是有一种方法引用创建了一个对象的构造函数,例如:
function Foo () {}
// default value of the property:
Foo.prototype.constructor == Foo; // true

这个属性被Foo的“实例”所继承,因此您可以知道使用哪个构造函数创建了一个对象:

var foo = new Foo();
foo.constructor == Foo;

如果您将一个新对象分配给函数的原型,这种关系将丢失:

function Bar () {}
Bar.prototype = { inherited: 1 };

Bar.prototype.constructor == Bar;    // false
Bar.prototype.constructor == Object; // true

它也会影响函数的实例:

var bar = new Bar();
bar.constructor == Bar;    // false
bar.constructor == Object; // true

另一个类似的情况是当您使用构造函数拥有两个或多个级别的继承时,最常见的方法是用于表示函数之间的继承关系,即将第二级别的 prototype 属性赋值,例如:

function Parent() {}

function Child () {}
Child.prototype = new Parent();

上述代码存在几个问题,首先它执行了父构造函数的逻辑来创建继承关系,但那是另一回事,在上面的例子中constructor属性也会受到影响,因为我们完全替换了Child.prototype对象。
var child = new Child();
child.constructor == Parent; // true

如果我们在分配后替换Child.prototypeconstructor属性值,它将显示预期行为:
function Child() {}
Child.prototype = new Parent();
Child.prototype.constructor = Child;

var child = new Child();
child.constructor == Child; // true

感谢您提供如此详细的解释,现在一切都清晰了。唯一仍然让我有点困惑的是Child.prototype.constructor = Child看起来有点循环。 - Nik So
1
@Nik,不用谢!是的,它确实是通过设计成为循环的,例如:Object.prototype.constructor.prototype.constructor.prototype.constructor == Object; ;-) - Christian C. Salvadó

2

我认为这与使用new关键字实例化Bar有关。我相信使用new会寻找Bar.prototype.constructor。在那行代码之前,与Bar.prototype.contructor链接的对象是Foo类型的,因此在没有那行代码的情况下实例化它将创建一个Foo对象而不是一个Bar对象。


谢谢Keith!这是一个简洁明了的解释。 - Nik So

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