我一直在阅读很多关于 javascript 中“继承”的文章。他们中的一些人使用new,而其他人则推荐Object.Create。我读得越多,我就越困惑,因为它似乎存在无穷无尽的变体来解决继承问题。
有人可以向我展示最接受的方式(或事实上的标准,如果有的话)?
(我想要一个Model可以扩展的基础对象RestModel或LocalStorageModel。)
我一直在阅读很多关于 javascript 中“继承”的文章。他们中的一些人使用new,而其他人则推荐Object.Create。我读得越多,我就越困惑,因为它似乎存在无穷无尽的变体来解决继承问题。
有人可以向我展示最接受的方式(或事实上的标准,如果有的话)?
(我想要一个Model可以扩展的基础对象RestModel或LocalStorageModel。)
JavaScript 是一种基于原型而非类的 OOP 语言。这是造成所有这些混乱的原因之一:许多开发人员使用 JS,因为它是基于类的。
因此,您可以看到很多库试图在 JS 中使用基于类的语言范式。
此外,JS 本身缺乏一些特性,这使得继承,也是基于原型的,很痛苦。例如,在Object.create没有办法从另一个对象创建对象之前(就像基于 OOP 原型的语言应该做的那样),而只能使用functionas 构造函数。
出于这个原因,你可以看到很多库都在尝试“修复”该语言,每个库都以自己的方式。
所以,你的困惑是正常的。也就是说,“官方”的方式是使用prototype属性,functions作为构造函数,并Object.create从对象的实例中创建。但是,如上所述,在某些情况下代码很冗长或缺少功能,因此此过程通常以某种方式包装,然后就变成了个人喜好问题。
因为您在谈论模型,所以您可以查看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();
现在,这里的问题:
Model被调用一次,只有当RestModel.prototype设置了。因此,foo每个RestModel实例的属性都是“foo”。RestModel实例都将在this.array属性中共享同一个数组的同一个实例。如果Model直接创建一个实例,则每个实例都有一个新的数组实例。myModel.constructor是Model而不是RestModel。那是因为我们prototype用一个新的 , 实例覆盖Model,它包含constructor等于Model。RestModel对构造函数进行惰性调用的新实例,是不可能的。我认为有一些要点,当然它们不是唯一的。那么,如何解决这些问题呢?正如我所说,很多人已经这样做了,他们创建库和框架也是为了限制冗长。但是,要有一个想法:
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);
请注意,如果您不想使用prototype或function作为构造函数,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();
在这种情况下,您基本上模仿了构造函数。您也可以将 a 传递descriptor给Object.create(请参阅文档),但它会变得更加冗长。大多数人使用某种extend函数或方法(正如您可能在 Backbone 示例中看到的那样)。
希望能帮助到你!
简单:Object.create并非在所有环境中都支持,但可以用new. 除此之外,两者有不同的目标:Object.create只是创建一个继承自其他对象的对象,同时还调用构造函数。使用合适的。new
在您的情况下,您似乎希望RestModel.prototype继承自Model.prototype. Object.create(或其垫片)是正确的方法,因为您不想 a)创建一个新实例(实例化 a new Model)和 b)不想调用 Model 构造函数:
RestModel.prototype = Object.create(Model.prototype);
如果你想在 RestModels 上调用 Model 构造函数,那与原型无关。使用call()or apply():
function RestModel() {
Model.call(this); // apply Model's constructor on the new object
...
}