我已经绘制了下面的图片,演示了如何继承对象(函数构造函数标记为蓝色,从这些构造函数创建的对象标记为绿色):
以下是创建此类层次结构的代码:
function Figure() {}
function Rect() {}
Rect.prototype = new Figure();
function Square() {}
Square.prototype = new Rect();
function Ellipse() {}
Ellipse.prototype = new Figure();
function Circle() {}
Circle.prototype = new Ellipse();
现在我想检查new Square()
是否继承Rect
,所以我希望JavaScript引擎能够检查它:
var s = new Square();
s instanceof Rect // ?
s.__proto__ === Rect.prototype // false
new Rect() new Figure()
s.__proto__.__proto__ === Rect.prototype // true
new Figure() new Figure()
因此s instanceof Rect
应该返回true
。这是预期的,实际上是我运行代码时返回的内容。但后来我想检查new Circle()
是否继承Rect
,所以我遵循相同的逻辑:
var c = new Circle();
c instanceof Rect // ?
c.__proto__ === Rect.prototype // false
new Ellipse() new Figure()
c.__proto__.__proto__ === Rect.prototype // true
new Figure() new Figure()
因此,使用此检查逻辑c instanceof Rect
应返回true
,但如果我实际运行代码,c instanceof Rect
将返回false。我误解了instanceof
运营商的机制吗?
答案 0 :(得分:8)
你的逻辑是正确的,但最初的假设有点不对劲。可以使用原型模拟基于常规类的继承。
为了重现您绘制的结构,我创建了以下代码:
function Figure() {}
function Rect() {}
function Square() {}
function Ellipse() {}
function Circle() {}
Ellipse.prototype = Rect.prototype = new Figure();
Square.prototype = new Rect();
Circle.prototype = new Ellipse();
console.log("is Figure: " + (new Circle() instanceof Figure));
console.log("is Ellipse: " + (new Circle() instanceof Ellipse));
console.log("is Rect: " + (new Circle() instanceof Rect));

如您所见,new Circle() instanceof Rect
在您配置时返回true。问题是通过将Ellipse.prototype
和Rect.prototype
设置为同一个对象,它们基本上变成了相同的类型(具有多个构造函数)。
那么你如何解决它?为原型创建不同的Figure
个实例,如下所示:
function Figure() {}
function Rect() {}
function Square() {}
function Ellipse() {}
function Circle() {}
Ellipse.prototype = new Figure();
Rect.prototype = new Figure();
Square.prototype = new Rect();
Circle.prototype = new Ellipse();
console.log("is Figure: " + (new Circle() instanceof Figure));
console.log("is Ellipse: " + (new Circle() instanceof Ellipse));
console.log("is Rect: " + (new Circle() instanceof Rect));

现在结果是每个人都期望的。
修改强>
我重新绘制了你的照片,并绘制了另一张照片,根据你的文字示例说明对象的实际情况,这与我的第二个代码相同。
原文:我突出了表达式Rect.prototype === new Circle().__proto__.__proto__
中的引用:
第二个:
<强> PS 强>
今天在2016年,不是Circle.prototype = new Ellipse()
是实现继承的方式,而是使用标准类继承:
class Figure {}
class Rect extends Figure {}
class Square extends Rect {}
class Ellipse extends Figure {}
class Circle extends Ellipse {}
console.log("new Circle is Figure: " + (new Circle() instanceof Figure));
console.log("new Circle is Rect: " + (new Circle() instanceof Rect));
&#13;
答案 1 :(得分:4)
根据您问题中的示例代码,c.__proto__.__proto__ === Rect.prototype
会返回false
。 new Figure
被调用两次,并创建两个不同的Figure
个实例。
不同的对象实例不相等。
function Figure() {}
function Rect() {}
Rect.prototype = new Figure();
function Square() {}
Square.prototype = new Rect();
function Ellipse() {}
Ellipse.prototype = new Figure();
function Circle() {}
Circle.prototype = new Ellipse();
var c = new Circle();
console.log('c instanceof Rect:', c instanceof Rect);
console.log('c.__proto__ === Rect.prototype', c.__proto__ === Rect.prototype);
console.log('c.__proto__.__proto__ === Rect.prototype', c.__proto__.__proto__ === Rect.prototype);
答案 2 :(得分:3)
Circles和Squares在他们的原型链中都有一个Figure的事实意味着c instanceof Figure
和s instanceof Figure
都是真的,但是他们每个都有自己的图,因为new Figure()
被调用两次。请注意new Figure() != new Figure()
,因为Javascript中的对象永远不会等于其他对象。以下是对图表的更新,其中显示了上述代码中实际发生的情况。您可以看到Circles和Squares在其原型链中各有一个独特的图形:
请注意,您可以稍微更改一下代码,以便重复使用一个数字作为Rect和Ellipse的原型,这将等同于原始帖子中的图表,并且会产生您期望看到的行为:
function Figure() {}
var f = new Figure();
function Rect() {}
Rect.prototype = f;
function Square() {}
Square.prototype = new Rect();
function Ellipse() {}
Ellipse.prototype = f;
function Circle() {}
Circle.prototype = new Ellipse();
console.log( (new Circle) instanceof Rect ); // true