JavaScript原型的继承 - 'constructor'属性? [英] JavaScript Inheritance with Prototypes -- 'constructor' property?
问题描述
我见过很多像这样的东西,我正在寻找基本的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 $ c的结果有关$ c>?
我发现自己在想,什么是正确的?我知道很多人会选择给每个食品类别(面包,寿司)等)一个新的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?
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屋!