您不能通过重新分配给prototype.constructor来更改构造函数
发生的事情是Rabbit.prototype.constructor 是指向原始构造函数(function Rabbit(){...})的指针,因此“类”的用户可以从实例中检测构造函数。因此,当您尝试这样做时:
Rabbit.prototype.constructor = function Rabbit() {
this.jumps = "no";
};
您只会影响依赖prototype.constructor 从实例动态实例化对象的代码。
调用new X时,JS引擎没有引用X.prototype.constructor,它使用X作为构造函数,X.prototype作为新创建对象的原型,忽略X.prototype.constructor。
解释这一点的一个好方法是自己实现new 运算符。 (克罗克福德会很高兴,不再是新的;)
// `new` emulator
//
// Doesn't reference `.constructor` to show that prototype.constructor is not used
// when istantiating objects a la `new`
function make(ctorFun, argsArray) {
// New instance attached to the prototype but the constructor
// hasn't been called on it.
const newInstance = Object.create(ctorFun.prototype);
ctorFun.apply(newInstance, argsArray);
return newInstance;
}
// If you create a utility function to create from instance, then it uses the
// inherited `constructor` property and your change would affect that.
function makeFromInstance(instance, argsArray) {
return make(instance.constructor, argsArray);
}
function X(jumps) {
this.jumps = jumps;
}
// Flip the constructor, see what it affects
X.prototype.constructor = function(jumps) {
this.jumps = !jumps;
}
const xFromConstructorIsGood = make(X, [true]);
const xFromInstanceIsBad = makeFromInstance(xFromConstructorIsGood, [true]);
console.log({
xFromConstructorIsGood,
xFromInstanceIsBad
});
JS 中的继承
有助于 JS 继承的库实现了继承,并且确实依赖于 prototype.constructor,其精神如下:
function extend(base, sub) {
function surrogateCtor() {}
// Copy the prototype from the base to setup inheritance
surrogateCtor.prototype = base.prototype;
sub.prototype = new surrogateCtor();
// The constructor property is set to the base constructor
// with the above trick, let's fix it
sub.prototype.constructor = sub;
}
您可以看到,在上面的代码中,我们必须修复构造函数属性,因为它有时用于在您只有一个实例时创建实例化对象。但它不会影响实际的构造函数。看我关于JS继承的帖子http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
如何重新定义构造函数
如果你真的想重新定义一个构造函数,就这样做
// If Rabbit had any custom properties on it
// (or static properties as some call it), they would not be copied, you'd have to do that manually using getOwnPropertyNames
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames
var oldProto = Rabbit.prototype;
Rabbit = function() {...};
Rabbit.prototype = oldProto;
请注意,这不会影响已复制该引用的代码,例如:
const myRefRabbit = Rabbit