正确的JavaScriptinheritance

我一直在阅读很多有关JavaScript的“inheritance”的文章。 其中一些使用new而其他人推荐Object.Create 。 我读得越多,我就越感到困惑,因为它似乎存在无数的变种来解决inheritance问题。

有人可以善意地向我展示最可接受的方式(或事实上的标准,如果有的话)?

(我想有一个基本对象Model ,我可以扩展RestModelLocalStorageModel 。)

简单: Object.create在所有环境中都不被支持,但是可以用new方式来擦除。 除此之外,两者有不同的目的: Object.create只是创build一个从另一个inheritance的对象,而new 调用一个构造函数。 使用适当的东西。

在你的情况下,你似乎希望RestModel.prototypeModel.prototypeinheritance。 因为你不想创build一个新的实例(实例化一个new Model ),并且不想调用模型构造函数, Object.create (或者它的shim)是正确的方法。

 RestModel.prototype = Object.create(Model.prototype); 

如果你想在RestModels上调用Model构造函数,那和原型没有任何关系。 使用call()apply()

 function RestModel() { Model.call(this); // apply Model's constructor on the new object ... } 

JavaScript是基于原型而不是类的OOP语言。 这是你可以看到的所有这些混乱的原因之一:很多开发人员使用JS,因为它是基于类的。

因此,你可以看到很多试图在JS中使用基于类的语言范例的库。

另外,JS本身缺乏一些使得inheritance的特性,也是原型的,痛苦的。 例如,在Object.create之前,没有办法从另一个对象创build一个对象(就像一个基于OOP原型的语言应该这样做),但只能使用一个function作为构造函数。

而且也是因为这个原因,你可以看到很多图书馆试图“固定”语言,每一个都以自己的方式。

所以,你的困惑是正常的。 说,“官方”方式是使用prototype属性, function s作为构造函数, Object.create从对象的inheritance来创build。 但是,如上所述,在某些情况下代码是冗长的或者缺乏function性的,所以这个程序经常被包装起来,然后就变成了个人品味的问题。

因为你正在谈论模型,你可以看看Backbone的模型 ,看看这种方法是否适合你。

更新 :举个例子,我希望能帮助你澄清一下,这里老派传承的方式是用new

 function Model() { this.foo = "foo"; this.array = []; } Model.prototype.foo = ""; Model.prototype.array = null; Model.prototype.doNothing = function() {}; function RestModel() { this.bar = "bar"; } RestModel.prototype = new Model; RestModel.prototype.bar = "" var myModel = new RestModel(); 

现在,这里的问题:

  1. 只有在设置了RestModel.prototype时, Model的构造函数才被调用一次。 因此,每个RestModel实例的foo属性将是“foo”。
  2. 不仅如此,而且所有 RestModel实例将共享this.array属性中相同数组的相同实例。 如果直接创buildModel实例,则每个实例都有一个新的数组实例。
  3. myModel.constructorModel而不是RestModel 。 这是因为我们用一个新的Model实例覆盖prototype ,其中包含的constructor等于Model
  4. 如果你想通过对构造函数的懒惰调用来获得RestModel的新实例,是不可能的。

我认为有一些要点,当然不是唯一的。 那么,如何解决这个问题呢? 正如我所说,很多人已经这样做了,他们创build图书馆和框架也限制了详细程度。 然而,有一个想法:

 function Model() { this.foo = "foo"; this.array = []; } Model.prototype.foo = ""; Model.prototype.array = null; Model.prototype.doNothing = function() {}; function RestModel() { Model.call(this); this.bar = "bar"; } RestModel.prototype = Object.create(Model.prototype); RestModel.prototype.constructor = RestModel; RestModel.prototype.bar = "" var myModel = new RestModel(); // for lazy constructor call var anotherModel = Object.create(RestModel.prototype); RestModel.call(anotherModel); 

注意,如果你不想使用prototypefunction作为构造函数,用Object.create你可以这样做:

 var Model = { foo: "", array: null, doNothing: function() {} } var RestModel = Object.create(Model); RestModel.bar = ""; var myModel = Object.create(RestModel); // Assuming you have to set some default values initialize(RestModel); 

要么:

 var Model = { foo: "", array: null, doNothing: function() {}, init : function () { this.foo = "foo"; this.array = []; }, } var RestModel = Object.create(Model); RestModel.bar = ""; RestModel.init = function () { Model.init.call(this); this.bar = "bar"; } var myModel = Object.create(RestModel); myModel.init(); 

在这种情况下,你基本上是模仿构造函数。 您也可以将descriptor传递给Object.create (请参阅文档 ),但它变得更加冗长。 大多数人使用某种extend函数或方法(正如您在Backbone示例中可能看到的那样)。

希望它有帮助!