Object.create 将prototype.constructor 更改为父构造函数,但在子实例化时,子构造函数运行

Posted

技术标签:

【中文标题】Object.create 将prototype.constructor 更改为父构造函数,但在子实例化时,子构造函数运行【英文标题】:Object.create changes prototype.constructor to parent constructor, but upon child instantiation, child constructor runs 【发布时间】:2014-01-16 19:14:58 【问题描述】:

我创建了一个示例来说明:

// this is the parent class
function animal()  console.log('animal constructor') 

// allow animals to walk
animal.prototype.walk = function()  console.log('animal walking') 

// create child class
function cat()  console.log('cat constructor') 

// cat inherits from animal
cat.prototype = Object.create(animal.prototype);

// let cats meow
cat.prototype.meow = function()  console.log('meow') 

// create a cat object
var myCat = new cat();

/* output: cat constructor */

// yet, the constructor that ran is different than what the prototype for cat reports
console.log(cat.prototype.constructor);

/* output: function animal()  console.log('animal constructor')  */

所以请注意继承是如何按预期工作的,cat 从其父 dog 类继承方法“walk”,并向子类添加更多方法(如 meow)按预期工作。但是,当我创建 cat 的实例时, cat 的构造函数运行,而 cat.prototype.constructor 指向从 dog“继承”的构造函数。

object.prototype.constructor 的目的不就是允许我们在声明对象后修改对象的构造函数而不清除对象的原型吗?在上面的例子中,存储在 cat.prototype.constructor 中的构造函数不应该指向创建 cat 对象时运行的同一个构造函数吗?这种明显的歧义是否与this source code 中此语句的运行方式有关:

// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;

【问题讨论】:

通常除了设置共享原型成员之外,您可能还想在子构造函数中重新使用父实例特定的构造函数代码:Animal.call(this).***.com/questions/16063394/… 【参考方案1】:

想一想:

cat.prototype = Object.create(animal.prototype);

Object.create(animal.prototype) 将简单地返回一个本身没有属性但其原型由animal.prototype 给出的对象。因此,在此对象上查找 constructor 属性将简单地返回 animal.prototype.constructor 中保存的值。

由于上面的行将对这个新创建的对象的引用分配给cat.prototype(并因此覆盖之前在cat.prototype 中保存的任何内容),当然您希望cat.prototype.constructor 等于animal.prototype.constructor .

正如你上面提到的,你可以使用类似的东西来回避这个“问题”:

cat.prototype.constructor = cat;

Object.create() 的引用:https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Global_Objects/Object/create

【讨论】:

【参考方案2】:

constructor 属性只是原型对象的一个​​简单属性。在幕后没有什么神奇的事情发生。这是一个可以被覆盖和重置的属性,但它不会影响其他任何东西。

所以当你这样做时:

cat.prototype = Object.create(animal.prototype);

您正在使用从animalprototype 对象派生的全新对象覆盖函数cat 的整个原型属性。但由于constructor 属性只是prototype 对象的普通属性,它也会被覆盖。

是的,在实现继承时,行

Class.prototype.constructor = Class;

通常用于将constructor 属性恢复为其原始值,并在某种程度上撤消此继承模式造成的“损害”。

因此,在您的情况下,您需要添加以下行:

cat.prototype = Object.create(animal.prototype);
cat.prototype.constructor = cat;  //  <---- add this

【讨论】:

以上是关于Object.create 将prototype.constructor 更改为父构造函数,但在子实例化时,子构造函数运行的主要内容,如果未能解决你的问题,请参考以下文章

Object.create()方法的低版本兼容问题

instanceof,Object.getPrototypeOf(),Object.create(),Object.setPrototypeOf(),Object.prototype.isProtot

Object.create()和setPrototypeof和Child.prototype = Parent.prototype和Child.prototype = new Parent()的区别(

Object备忘录

JavaScript OOP

Object.create(null)