为什么不能从原型更改构造函数? [英] Why is it impossible to change constructor function from prototype?

查看:45
本文介绍了为什么不能从原型更改构造函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的例子.

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 成为公开的.我是这样做的:

I want to change the code in Rabbit() so that the var jumps becomes public. I do it this way:

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

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

Why is it not possible to change the code in constructor function this way?

推荐答案

您不能通过重新分配给 prototype.constructor

You cannot change a constructor by reassigning to prototype.constructor

发生的事情是 Rabbit.prototype.constructor 是一个指向原始构造函数的指针(function Rabbit(){...}),因此用户类"可以从实例中检测构造函数.因此,当您尝试执行以下操作时:

What is happening is that Rabbit.prototype.constructor is a pointer to the original constructor (function Rabbit(){...}), so that users of the 'class' can detect the constructor from an instance. Therefore, when you try to do:

Rabbit.prototype.constructor = function Rabbit() {
    this.jumps = "no";
};

您只会影响依赖 prototype.constructor 从实例动态实例化对象的代码.

You're only going to affect code that relies on prototype.constructor to dynamically instantiate objects from instances.

当你调用new X时,JS引擎不引用X.prototype.constructor,而是使用X作为构造函数function 和 X.prototype 作为新创建的对象的原型.,忽略 X.prototype.constructor.

When you call new X, the JS engine doesn't reference X.prototype.constructor, it uses the X as the constructor function and X.prototype as the newly created object's prototype., ignoring X.prototype.constructor.

解释这一点的一个好方法是自己实现 new 运算符.(克罗克福德会很高兴的,没有新的了;)

A good way to explain this is to implement the new operator ourselves. ( Crockford will be happy, no more 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,其精神如下:

Libraries that help with JS inheritance implement inheritance and do rely on prototype.constructor with something in the spirit the following:

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

You can see that in the above code, we have to fix the constructor property because it's sometimes used to create instantiate an object when you only have an instance. but it doesn't affect the actual constructor. See my post about JS inheritance http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

如何重新定义构造函数如果你真的想重新定义一个构造函数,就做

How to redefine a constructor If you really want to redefine a constructor, just do

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

请注意,这不会影响已经复制该引用的代码,例如:

Note that this would not affect code that had already copied that reference, for example:

const myRefRabbit = Rabbit

这篇关于为什么不能从原型更改构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆