【问题标题】:JavaScript Multi-level inheritance and isPrototypeOfJavaScript 多级继承和 isPrototypeOf
【发布时间】:2015-05-21 06:19:59
【问题描述】:

我有一个用 JavaScript 实现的多级继承,如下所示

function MovingObject(){

}

function Vehicle(){

}
Vehicle.prototype = Object.create(MovingObject);

function Car(){

}
Car.prototype = Object.create(Vehicle);

var c = new Car();

Car 是 Vehicle 的子代,而 Vehicle 又是 MovingObject 的子代,所以我希望 Car 是 MovingObject 的间接子代。

以下语句返回 true,表明 Car 是 Vehicle 的直接子代

Vehicle.isPrototypeOf(c);

但是,下面的语句不返回 true

MovingObject.isPrototypeOf(c);

知道为什么它不返回 true,以及如何让它返回 true

【问题讨论】:

  • 应该是Vehicle.prototype = Object.create(MovingObject.prototype),和其他一样。
  • 即使使用 Vehicle.prototype = Object.create(MovingObject.prototype),我该如何编写代码来测试 Car 和 MovingObject 实例之间的关系?

标签: javascript inheritance multi-level


【解决方案1】:

这是关于 JavaScript 的常见问题。

MovingObjectVehicle构造函数,但它们不是原型。

也就是说,您应该使用Object.create(ConstructorFunction.prototype) 而不是仅使用ConstructorFunction 进行派生。

在 JavaScript 中,即使一个函数也是一个对象,这就是为什么 Object.create(...) 在您提供构造函数时起作用的原因。结果对象将以构造函数对象为原型。

实际上,您既可以使用Object.create(ConstructorFunction.prototype) 方法,也可以使用new 实现相同的目标:

Vehicle.prototype = new MovingObject();

new 方法的主要问题是您正在使用构造函数创建一个新对象,并且您可能正在向原型添加不需要的数据和行为:

function MovingObject() {
  this.x = 11;
}

function Vehicle() {}
Vehicle.prototype = new MovingObject();

var instance = Object.create(Vehicle.prototype);

// What? instance has "x" property!!
document.getElementById("result").textContent = instance.x;
<div id="result"></div>

更新

OP 在一些评论中说:

这是否意味着我们无法建立真正的 is-a 关系 Car 和 MovingObject 在这里?如果是,我们如何使用代码对其进行测试? 意思是,只有当 Car 是一个移动对象时,我才想执行一些代码。 我怎样才能完成测试?

检查并执行以下代码sn -p更清楚:

function A() {}

function B() {}
B.prototype = Object.create(A.prototype);

function C() {}
C.prototype = Object.create(B.prototype);

var instanceOfB = Object.create(B.prototype);
var instanceOfC = Object.create(C.prototype);

var result1 = A.prototype.isPrototypeOf(instanceOfC);
var result2 = B.prototype.isPrototypeOf(instanceOfC);
var result3 = A.prototype.isPrototypeOf(instanceOfB);

document.getElementById("result1").textContent = result1;
document.getElementById("result2").textContent = result2;
document.getElementById("result3").textContent = result3;
<h2>A is prototype of instanceOfC?</h2>
<div id="result1"></div>
<h2>B is prototype of instanceOfC?</h2>
<div id="result2"></div>
<h2>A is prototype of instanceOfB?</h2>
<div id="result3"></div>

更新 2

正如@RobertRossmann 对此答案的注释,同样的代码 sn-p 可以使用instanceof 运算符来实现,它的附加值是有效地检查实例是否属于提供构造函数的某个原型:

function A() {}

function B() {}
B.prototype = Object.create(A.prototype);

function C() {}
C.prototype = Object.create(B.prototype);

var instanceOfB = Object.create(B.prototype);
var instanceOfC = Object.create(C.prototype);

var result1 = instanceOfC instanceof B;
var result2 = instanceOfC instanceof C;
var result3 = instanceOfB instanceof A;
var result4 = instanceOfC instanceof A;

document.getElementById("result1").textContent = result1;
document.getElementById("result2").textContent = result2;
document.getElementById("result3").textContent = result3;
document.getElementById("result4").textContent = result4;
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>
<div id="result4"></div>

【讨论】:

  • 这是否意味着我们不能在这里建立真正的 is-a 关系 Car 和 MovingObject ?如果是,我们如何使用代码对其进行测试?意思是,只有当 Car 是一个移动对象时,我才想执行一些代码。我怎样才能通过测试?
  • @AtulP 我相信我的回答已经回答了这个问题,但我已经用一个关于您的担忧的示例对其进行了更新:)
  • 我相信instanceof 运算符在这里也可能有用——它基本上是一个很好的语法糖,用于递归检查完整的原型链。而且,它作用于实例和构造函数
  • @RobertRossmann 是的...我用isPrototypeOf 制作了样本,因为 OP 正在使用它,所以我可以向 OP 展示它应该可以工作...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-13
  • 2017-05-02
  • 2013-02-09
  • 1970-01-01
  • 2021-01-29
  • 1970-01-01
相关资源
最近更新 更多