.constructor 属性实际上并不重要,并且与从 JavaScript 中的其他对象继承关系不大。它只是一个对象构造函数的方便句柄。
例如,如果您有某事物的一个实例,并且您想创建该事物的另一个实例,但您没有直接处理它的构造函数,您可以执行以下操作:
const myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]
const car2 = new myCar.constructor();
console.log(car2.constructor); // [Function: Racecar]
了解.constructor 属性和对象的类不是同义词很重要。正如您可能已经猜到的那样,.constructor 属性是动态的,就像 JavaScript 中的大多数其他东西一样,所以它不应该用于类型检查等任何事情。
了解.constructor 属性并不意味着某事物是其他事物的子类也很重要。事实上,在 JavaScript 中没有可靠的方法来确定某事物是否是其他事物的子类。因为它是一种动态语言,并且因为有很多方法可以从其他对象继承属性(包括在实例化后从其他对象复制属性),所以 JavaScript 中不像其他语言那样存在类型安全子类。
了解某项是否兼容类型的最佳方法是对属性进行特性测试。也就是鸭式。
instanceof 运算符忽略 .constructor 属性。相反,它会检查构造函数的.prototype 是否存在于对象的原型链中(通过身份检查)。
使用手动构造函数,继承会混淆.constructor 属性连接(使其引用错误的构造函数)。您可以通过手动连接连接来修复它。例如,在 ES5 中这样做的规范方式是这样的:
function Car () {}
console.log(Car.prototype.constructor); // Car
function Racecar () {}
Racecar.prototype = Object.create(Car.prototype);
// To preserve the same relationship we have with the Car
// constructor, we'll need to reassign the .prototype.constructor:
Racecar.prototype.constructor = Racecar;
var myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]
ES6 类会自动为您执行此操作:
// ES6
class Car {}
class Racecar extends Car {}
const myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]
也就是说,我不是构造函数或 ES6 类的忠实粉丝,而且我通常很少使用 .constructor 属性。为什么?因为工厂函数更灵活、更强大,而且它们没有与构造函数和类继承相关的陷阱。见"Factory Functions vs Constructor Functions vs Classes"。