javascript - 为什么无法从原型(prototype)更改构造函数?

标签 javascript oop prototype

我有这样的例子。

function Rabbit() {
    var jumps = "yes";
};
var rabbit = new Rabbit();
alert(rabbit.jumps);                    // undefined
alert(Rabbit.prototype.constructor);    // outputs exactly the code of the function Rabbit();

我想更改 Rabbit() 中的代码,以便将 var jumps 公开。我这样做:

Rabbit.prototype.constructor = function Rabbit() {
    this.jumps = "no";
};
alert(Rabbit.prototype.constructor);    // again outputs the code of function Rabbit() and with new this.jumps = "no";
var rabbit2 = new Rabbit();             // create new object with new constructor
alert(rabbit2.jumps);                   // but still outputs undefined

为什么不能以这种方式更改构造函数中的代码?

最佳答案

您不能通过重新分配给 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 作为新创建对象的原型(prototype)。忽略 X.prototype.constructor

解释这一点的一个好方法是我们自己实现 new 运算符。 ( Crockford 会很高兴,不再新;)

// `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;
}

您可以看到,在上面的代码中,我们必须修复 constructor 属性,因为当您只有一个实例时,它有时用于创建实例化对象。但它不影响实际的构造函数。请参阅我关于 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

关于javascript - 为什么无法从原型(prototype)更改构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9267157/

相关文章:

javascript - 编辑 Vista 按钮的 Javascript

Java 菜鸟需要澄清奇怪的重载方法问题

javascript - 在javascript中制作特殊的函数原型(prototype)

javascript - JavaScript 中有没有没有原型(prototype)的对象吗?

javascript - 修改express.js中的res对象

javascript - 表单数据的本地存储

python - __new__ 覆盖不起作用

javascript - 如何在 javascript 中修复此类定义以支持 instanceof 运算符

javascript - CSS 转换未在所有浏览器中使用 jQuery 更新

java - 如何在 Java 中从另一个类创建和构造一个类