也许我做错了。我想设置一个基类和两个继承自该类的类。然而,它告诉我,一个孩子是另一个孩子的一个例子......这可能不正确,可以吗?我在这做错了什么?
function BaseClass(){}
function Child1(){}
Child1.prototype = BaseClass.prototype;
Child1.prototype.constructor = Child1;
function Child2(){}
Child2.prototype = BaseClass.prototype;
Child2.prototype.constructor = Child2;
console.log((new Child1() instanceof Child2)); // true
答案 0 :(得分:3)
您已将两个类的原型设置为完全相同的对象(“BaseClass.prototype”),并将其上的“constructor”属性设置为“Child2”。换句话说,“Child1.prototype”和“Child2.prototype”是相同的,因此代码中只涉及一个“构造函数”属性,最终它是“Child2”。
也许您想将这些原型设置为BaseClass的实例?
Child1.prototype = new BaseClass();
Child1.prototype.constructor = Child1;
Child2.prototype = new BaseClass(); // a different object
Child2.prototype.constructor = Child2;
(@ Raynos指出实例化这样的原型值可能会导致细微的问题,所以你可能更喜欢在他的答案中使用这种方法。)
答案 1 :(得分:2)
Child1.prototype = BaseClass.prototype;
应为Child1.prototype = Object.create(BaseClass.prototype)
您不希望原型对象相同,您想要一个继承自BaseClass
的新原型对象
免责声明: Object.create
是ES5,使用ES5-shim进行旧版平台支持。
为您提供更全面的示例:
// Create base prototype
var Base = {
method: function () {
return this.things;
},
constructor: function (things) {
this.things = things;
}
};
// Link constructor and prototype
Base.constructor.prototype = Base;
// Create child prototype that inherits from Base
var Child = Object.create(Base);
// overwrite constructor
Child.constructor = function (things) {
things++;
Base.constructor.call(things);
}
// Link constructor and prototype
Child.constructor.prototype = Child;
// Swap prototype and constructor around to support new
ChildFactory = Child.constructor;
var c = new ChildFactory(41);
console.log(c.method()); // 42
<强>目视:强>
var Base = { ... }
这里我们简单地用方法和属性创建一个对象。我们希望能够创建此对象的实例。所以Base
是一个“类”,可以从实例(包括constructor
)访问它的所有方法和属性。
Base.constructor.prototype = Base;
您需要链接“构造函数”,这是一个可以使用new
调用的函数,它将为您提供对象ConstructorFunction.prototype
的新实例以及原型对象。这基本上是你需要手动完成的一些粘合剂,因为ES不会为你做这件事。
如果您忘记这样做,那么构造函数(X.constructor
)没有.prototype
属性来使实例继承。
var Child = Object.create(Base);
创建[[Prototype]]
为Base
的新对象。这基本上是原型链的开始
Child -> ([[Prototype]] = Base) -> ([[Prototype]] = Object.prototype) -> null
Child.x = ...
现在我们向子对象添加属性,这些属性是Child将继承的方法实例。基本上我们正在创建一个新的原型对象来继承。所有实例都将共享方法,并在原型链中共享方法(包括Base
)。
ChildFactory = Child.constructor;
new
关键字只适用于构造函数而不是原型对象,所以我们基本上要说“将我们的原型对象变量切换到构造函数变量”
就个人建立“类”时,我发现原型对象非常适合直接处理,在创建实例时,我发现构造函数很难处理。
现在我们致电var c = new Child(41);
它将调用我们定义的构造函数,它将递增things
,然后调用基础构造函数。
此时请注意c的原型链看起来像
c -> ([[Prototype]] = Child)
-> ([[Prototype]] = Base)
-> ([[Prototype]] = Object.prototype)
-> null
答案 2 :(得分:1)
如果你分配给原型,那是不是意味着你完全覆盖它?因此Child1和Child2实际上变成了BaseClass对象,而不是子类。
另见http://www.zipcon.net/~swhite/docs/computers/languages/object_oriented_JS/inheritance.html。 JS中适当的OO需要付出相当大的努力。
答案 3 :(得分:1)
这并不意味着检查对象new Child1()
是否由“Child1”构造函数创建。 instanceof
运算符只接受一个对象原型 - (new Child1()).[[Prototype]]
并检查它在原型链中的存在,主题为“Child1.prototype”的检查。通过构造函数的内部[[HasInstance]]方法激活运算符instanceof
。
因此,您需要以下列方式更改代码:
function BaseClass(){}
function Child1(){}
Child1.prototype = new BaseClass();
Child1.prototype.constructor = Child1;
function Child2(){}
Child2.prototype = new BaseClass();
Child2.prototype.constructor = Child2;
console.log((new Child1() instanceof Child2)); // false
这将是在javascript中正确实现OOP