正确的javascript继承

IT技术 javascript
2021-01-12 23:41:31

我一直在阅读很多关于 javascript 中“继承”的文章。其中一些使用,new而另一些则推荐Object.Create我读得越多,我就越困惑,因为似乎存在无穷无尽的变体来解决继承问题。

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

(我想要一个Model可以扩展的基础对象RestModelLocalStorageModel。)

2个回答

简单:Object.create并非在所有环境中都受支持,但可以用new. 除此之外,两者有不同的目的:Object.create只是创建一个继承自其他对象的对象,同时调用构造函数。使用合适的。new

在您的情况下,您似乎希望RestModel.prototype继承自Model.prototype. Object.create(或其垫片)是正确的方法,因为您不想 a)创建一个新实例(实例化 a new Model)和 b)不想调用模型构造函数:

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

如果您想在 RestModels 上调用 Model 构造函数,那与原型无关。使用call()apply()为此:

function RestModel() {
    Model.call(this); // apply Model's constructor on the new object
    ...
}
我认为这个答案总结为“使用合适的”。有时您需要构造函数中的逻辑,有时则不需要。+1
2021-03-11 23:41:31
为什么Object.Createnew那种情况好?如果我也想支持构造函数怎么办?而且该构造函数将在这两个被称为RestModelModel(如果我创建一个RestModel)。我通常是 C# 开发人员,所以我真的不明白其中的区别。我想定义基本原型并使用构造函数,但我不明白我是如何得到两者的?
2021-04-01 23:41:31

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();

现在,这里的问题:

  1. 的构造函数Model只在RestModel.prototype设置时调用一次因此,foo每个RestModel实例属性都是“foo”。
  2. 不仅如此,所有 RestModel实例都将在this.array属性中共享同一个数组的同一个实例如果Model直接创建一个实例,则每个实例都有一个新的数组实例。
  3. myModel.constructorModel而不是RestModel. 那是因为我们prototypeModel包含constructor等于 的的新实例覆盖Model
  4. 如果你想有一个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);

请注意,如果您不想使用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();

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

希望能帮助到你!

所有这些都是有效的,但以某种形式或另一种形式,它们最终会变得冗长。例如,如果RestModel有很多新的属性或方法,您可以进行成像这就是我说 JS 仍然缺乏某些东西时所说的。为了消除冗长,或者您决定使用 3rd 方库,或者您创建了几个实用函数来做到这一点。我将避免使用纯粹的new方法(第一种),而只是决定采用第二个还是第三个,这取决于您是否觉得拥有“类似于”“类”(所以是第二个)或不“类似”(第三个)的东西更舒服。
2021-03-14 23:41:31
你推荐我使用哪个例子?
2021-04-09 23:41:31