老实说,该.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
属性。为什么?因为工厂函数更灵活、更强大,而且它们没有与构造函数和类继承相关的陷阱。请参阅“工厂函数与构造函数与类”。