【问题标题】:JS: Why do you need to reset the constructor back after inheriting another prototype?JS:为什么在继承另一个原型后需要重新设置构造函数?
【发布时间】:2021-02-02 20:23:51
【问题描述】:

在下面的例子中,为什么需要Dog.prototype.constructor = Dog ?我在我们使用: Dog.prototype = Object.create(Animal.prototype) 继承 sayAnimal() 和添加到 Animal 原型的任何其他函数,但这对构造函数有何影响?忽略它会做什么?

function Animal(gender) {
    this.gender = gender;
}

Animal.prototype.sayAnimal = function() {
    return "I am an animal"
}

function Dog(gender, barkSound) {
    Animal.call(this, gender)
    this.barkSound = barkSound
}

Dog.prototype = Object.create(Animal.prototype) 

Dog.prototype.constructor = Dog 

【问题讨论】:

  • 如果你这样做,我建议你改用class

标签: javascript


【解决方案1】:

类的用户会期望实例的.constructor 属性引用该实例的构造函数。例如:

class ExtendedArray extends Array {
}

const e = new ExtendedArray();
console.log(e.constructor === ExtendedArray);

如果您使用functions 并手动扩展,那么如果您没有在子类原型上显式设置构造函数属性,.constructor 将不会引用子类构造函数(作为代码的用户通常会期望),但是对于超类:

function Animal(gender) {
}
function Dog(gender, barkSound) {
    Animal.call(this, gender)
}
Dog.prototype = Object.create(Animal.prototype)

// oops, this refers to Animal...
console.log(Dog.prototype.constructor);

也就是说,可能在大多数情况下都不是问题。

【讨论】:

  • 谢谢。起初,我认为创建Dog 的新实例会产生问题,但由于Dog 使用Dog.constructor,这并没有改变……什么会使用Dog.prototype.constructor
  • 实例的用户,当它不确定它是什么实例时。它可以使用实例的.constructor 属性来获取构造函数。这种情况在我的经验中是非常不寻常的,我从来没有遇到过需要它(除了像 JS 琐事问题这样愚蠢的事情)
【解决方案2】:
Dog.prototype = Object.create(Animal.prototype) 

导致整个 prototype 对象被Animal.prototype 的新实例替换,这很重要,这样您就不会从已更改的Animal.prototype 实例开始从原来的定义。此时,如果您要创建一个新的DogAnimal 构造函数将触发,并且您不会在新实例中获得Dog 的任何特征,您只会有另一个@ 987654329@.

但是,当你添加这个时:

Dog.prototype.constructor = Dog 

您只是替换了Animal.prototype 的构造函数部分,所以现在当您创建一个新的Dog 时,您首先创建了一个Animal 的新实例,但是使用Dog 构造函数,所以您的Animal 可以作为更具体的类型进行增强和使用。

我已经写了更多关于 here 的内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-17
    • 1970-01-01
    • 2012-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多