看一下下面的图片,取自以下答案 https://stackoverflow.com/a/8096017/783743:
当你创建一个新函数时,JavaScript 也会自动创建一个新对象(原型):
- JavaScript 设置
prototype
构造函数的属性传递给原型对象。
- JavaScript 设置
constructor
原型对象的属性传递给构造函数。
因此,当你这样做时:
function Foo() {}
JavaScript 实际上是这样做的:
function Foo() {}
Foo.prototype = { constructor: Foo };
JavaScript 为什么要这样做?考虑一下当你创建一个实例时会发生什么Foo
:
var foo = new Foo;
当您创建一个实例时Foo
使用new
关键字,JavaScript 实际上创建了一个实例Foo.prototype
并不是Foo
。这意味着foo
继承属性Foo.prototype
并不是Foo
。为了明确这一点:
function Foo() {}
Foo.bar = true;
Foo.prototype.baz = true;
var foo = new Foo;
console.log(foo.bar); // undefined
console.log(foo.baz); // true
现在的优势是拥有constructor
原型上的属性是当您创建一个实例时Foo
,该实例继承了constructor
来自原型的属性。因此,您可以使用它来找出对象的类型:
function Foo() {}
function Bar() {}
function test(obj) {
switch (obj.constructor) {
case Foo: console.log("It's a Foo."); break;
case Bar: console.log("It's a Bar."); break;
default: console.log("It's something else.");
}
}
test(new Foo);
test(new Bar);
test(new Object);
除此之外,没有什么特别之处constructor
原型的属性。这只是一个普通的财产。用泰勒·德登的话来说:https://www.youtube.com/watch?v=4X2AvfSTi6Q https://www.youtube.com/watch?v=4X2AvfSTi6Q
由于它是一个普通属性,您可以决定根本不具有构造函数属性:
function Foo() {}
Foo.prototype = {}; // no constructor property
您可以决定让它指向其他一些函数:
function Foo() {}
function Bar() {}
Foo.prototype.constructor = Bar;
您可以决定让它指向函数以外的其他东西:
function Foo() {}
Foo.prototype.constructor = "I am not a function.";
然而,重点是它只是另一个原型属性。事实上,我们可以利用这一点来创建更清晰的代码。例如,这就是我们通常在 JavaScript 中创建“类”的方式。
function MyClass(a, b) {
this.a = a;
this.b = b;
}
MyClass.prototype.sum = function () {
return this.a + this.b;
};
MyClass.prototype.diff = function () {
return this.a - this.b;
};
不是很干净。但请注意,所有三个函数MyClass
, sum
and diff
是原型函数:constructor
, sum
and diff
分别。原型只是一个对象,JavaScript 中的对象字面量提供了一种很好的封装形式。我们可以利用这一点来编写更清晰的代码:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
var MyClass = defclass({
constructor: function (a, b) {
this.a = a;
this.b = b;
},
sum: function () {
return this.a + this.b;
},
diff: function () {
return this.a - this.b;
}
});
这样就干净多了。此外,它还向我们表明constructor
property 只是一个普通的原型属性。希望这能回答你的问题。