了解原型继承

时间:2016-06-28 19:01:19

标签: javascript inheritance

我已经绘制了下面的图片,演示了如何继承对象(函数构造函数标记为蓝色,从这些构造函数创建的对象标记为绿色):

enter image description here

以下是创建此类层次结构的代码:

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运营商的机制吗?

3 个答案:

答案 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.prototypeRect.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__中的引用:

enter image description here

第二个:

enter image description here

<强> PS

今天在2016年,不是Circle.prototype = new Ellipse()是实现继承的方式,而是使用标准类继承:

&#13;
&#13;
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;
&#13;
&#13;

答案 1 :(得分:4)

根据您问题中的示例代码,c.__proto__.__proto__ === Rect.prototype会返回falsenew 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 Figures instanceof Figure都是真的,但是他们每个都有自己的图,因为new Figure()被调用两次。请注意new Figure() != new Figure(),因为Javascript中的对象永远不会等于其他对象。以下是对图表的更新,其中显示了上述代码中实际发生的情况。您可以看到Circles和Squares在其原型链中各有一个独特的图形:

enter image description here

请注意,您可以稍微更改一下代码,以便重复使用一个数字作为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