JavaScript原型的继承 - 'constructor'属性? [英] JavaScript Inheritance with Prototypes -- 'constructor' property?

查看:104
本文介绍了JavaScript原型的继承 - 'constructor'属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我见过很多像这样的东西,我正在寻找基本的JavaScript继承的正确解决方案:

I've seen a lot of stuff like this, and am looking for the proper solution to basic JavaScript inheritance:

function Food(){}  // Food  constructor (class)
function Bread(){} // Bread constructor (class)

var basicFood = new Food();    // Food classes will inherit from this basicFood instance.

Bread.prototype = basicFood; // Bread now inherits from Food.

var bread = new Bread();     // We create some bread!
bread.constructor == Food;  // Though, now we feel very uneasy about how
                           // the constructor is wrong,

Bread.prototype.constructor = Bread; // So we explicitly set the prototype's constructor
bread = new Bread();                // and when we create our new bread,
bread.constructor == Bread;        // we feel much better as the constructor appears correct.

// The issue? Suppose we have another food item, 
 // like in a real inheritance situation:

function Sushi(){};                    // We might be
Sushi.prototype = basicFood;          // tempted to do
Sushi.prototype.constructor = Sushi; // the same thing
var sushi = new Sushi();            // again

sushi.constructor == Sushi;  // Before we realize
bread.constructor == Sushi; // that we've ruined our bread.

basicFood.constructor != Food; // More importantly, we've really ruined all our basicFood,
                              // because while it's a prototype, 
                             // it's also an object in its own right,
                            // and deserves an accurate constructor property.



谁是构造函数应该是真的?



并且构造函数 instanceof

我发现自己在想,什么是正确的?我知道很多人会选择给每个食品类别(面包,寿司)等)一个新的Food实例,而不是给它们所有相同的basicFood实例..我想要这个更优化的解决方案(不做不需要的实例)。

I find myself wondering, what is correct? I understand that many would choose to give each food class (Bread, Sus etc) a new instance of Food, rather than giving them all the same basicFood instance.. I want this more optimal solution (not making unneeded instances).

鉴于我们的食物,面包,寿司和基本食物:

Given our Food, Bread, Sus and basicFood:

function Food(){}
function Bread(){}
function Sushi(){}
var basicFood = new Food();

我想我可以创建一个实例助手, 将在新实例上定义一个不可枚举的不可写不可配置属性'构造函数':

I figured I could create an instancing helper, which would define a non-enumerable non-writable non-configurable property 'constructor' on the new instance:

Bread.prototype = basicFood; // We still simply inherit from basicFood
Sushi.prototype = basicFood;


// But we use this helper function when we make instances
function reconstructify(target, Constructor){
  return Object.defineProperty(target, 'constructor', {
    enumerable:   false,
    configurable: false,
    writable:     false,
    value:        Constructor
  });
}

var bread = reconstructify(new Bread(), Bread); // Like so
var sushi = reconstructify(new Sushi(), Sushi);

在测试中,我意识到 instanceof 表现不像我想象的那样:

In testing this, I realized instanceof is not behaving the way I thought it might:

// True expressions for testing -- all good
basicFood.constructor == Food;
bread.constructor     == Bread;
sushi.constructor     == Sushi;

basicFood instanceof Food; // good also
bread instanceof Food;
sushi instanceof Food;

sushi instanceof Bread; // uh oh, not so good that this is true
bread instanceof Sushi; // why is this?

进一步研究,我似乎无法获得 instanceof 以我假设的方式工作:

Looking into it more, I can't seem to get instanceof to work the way I'd assume at all:

function Food(){}
function Bread(){}
function Sushi(){}

var basicFood = new Food();

Bread.prototype = basicFood;
Sushi.prototype = basicFood;

var bread = new Bread();
var sushi = new Sushi();

sushi instanceof Bread; // why true?
bread instanceof Sushi; // why true?

我想面包 sushi 两者都是Food的实例 - 而不是彼此。

I want bread and sushi to both be instances of Food -- not each other.

如何实现JavaScript继承维护构造函数属性以及 instanceof 运算符的预期行为?

How can I achieve JavaScript inheritance while maintaining the expected behavior for the constructor property as well as the instanceof operator?

推荐答案

让我们稍微检查你的代码。

Lets examine your code a little bit.

function Food(){}
function Bread(){}
function Sushi(){}
var basicFood = new Food();
Bread.prototype = basicFood;
Sushi.prototype = basicFood;

注意:当您设置与两个对象的原型相同的对象时,在一个原型中的增强,也将反映在另一个原型中。例如,

Note: When you set the same object as the prototype of two objects, augmentation in one prototype, will reflect in the other prototype as well. For example,

Bread.prototype = basicFood;
Sushi.prototype = basicFood;
Bread.prototype.testFunction = function() {
    return true;
}
console.log(Sushi.prototype.testFunction()); // true

让我们回到你的问题。

var bread = reconstructify(new Bread(), Bread);
var sushi = reconstructify(new Sushi(), Sushi);
console.log(sushi instanceof Bread);    // Why true?
console.log(bread instanceof Sushi);    // Why true?

根据 instanceof 来自MDN的文档

As per the instanceof docs from MDN,


instanceof运算符测试一个对象在其原型链中是否具有构造函数的prototype属性。

The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.

所以当我们做类似的事情时

So when we do something like

object1 instanceof object2

JavaScript将尝试查找 object2 的原型是否在<$ c的原型链中$ c> object1

JavaScript will try to find if the prototype of the object2 is in the prototype chain of object1.

在这种情况下,它只返回 true Bread.prototype 位于 sushi 的原型链中。我们知道 sushi 是由 Sushi 构建的。因此,它需要 Sushi 的原型并检查它是否等于面包的原型。因为,它们都指向相同的 basicFood 对象,它返回 true 。同样的情况, bread instanceof Sushi

In this case, it will return true only when the Bread.prototype is in the prototype chain of sushi. We know that sushi is constructed from Sushi. So, it will take Sushi's prototype and check if it is equal to Bread's prototype. Since, they both point to the same basicFood object, that returns true. Same case for, bread instanceof Sushi as well.

所以,正确的继承方式就是这样

So, the right way to inherit would be, like this

function Food()  {}
function Bread() {}
function Sushi() {}

Bread.prototype = Object.create(Food.prototype);
Bread.prototype.constructor = Bread;
Sushi.prototype = Object.create(Food.prototype);
Sushi.prototype.constructor = Sushi;

var bread = new Bread();
var sushi = new Sushi();

console.log(sushi instanceof Bread);  // false
console.log(bread instanceof Sushi);  // false
console.log(sushi.constructor);       // [Function: Sushi]
console.log(bread.constructor);       // [Function: Bread]
console.log(sushi instanceof Food);   // true
console.log(bread instanceof Food);   // true
console.log(sushi instanceof Sushi);  // true
console.log(bread instanceof Bread);  // true

这篇关于JavaScript原型的继承 - 'constructor'属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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