13

私はjavascriptの「継承」に関する記事をたくさん読んでいます。それらのいくつかは使用しますがnew、他は推奨しObject.Createます。継承を解決するためのバリアントが無限に存在するように見えるため、読むほど混乱します。

誰かが私に最も受け入れられている方法(または、ある場合は事実上の標準)を教えてくれませんか?

Model(拡張できるベースオブジェクトが欲しい、RestModelまたはLocalStorageModel。)

4

2 に答える 2

11

シンプル:Object.createすべての環境でサポートされているわけではありませんが、でシムすることができますnew。それとは別に、この2つには異なる目的があります。Object.create他のオブジェクトを継承するオブジェクトを作成するだけでなく、コンストラクター関数呼び出します。適切なものを使用してください。new

あなたの場合、あなたはそれがRestModel.prototypeから継承することを望んでいるようですModel.prototypeObject.create(またはそのシム)が正しい方法です。これは、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
    ...
}
于 2012-06-05T14:06:08.587 に答える
11

JavaScriptは、クラスではなくプロトタイプに基づくOOP言語です。これが、このような混乱の原因の1つです。多くの開発者は、クラスベースであるためJSを使用しています。

したがって、JSでクラスベース言語のパラダイムを使用しようとしている多くのライブラリを見ることができます。

さらに、JS自体には、継承をプロトタイプベースで苦痛にするいくつかの特性が欠けています。たとえば、以前Object.createは(OOPプロトタイプベースの言語で行う必要があるように)別のオブジェクトからオブジェクトを作成する方法はありませんでしたが、functionコンストラクターとしてのみ使用していました。

また、そのため、言語を「修正」しようとしている多くのライブラリを、それぞれ独自の方法で見ることができます。

だから、あなたの混乱は正常です。たとえば、「公式」の方法は、コンストラクターとしてprototypeプロパティsを使用し、オブジェクトのインスタンスから作成することです。ただし、前述のように、コードが冗長であるか、機能が不足している場合があるため、この手順は何らかの形でラップされることが多く、個人的な好みの問題になります。functionObject.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、が設定されている場合にのみ1回呼び出さRestModel.prototypeれます。したがって、fooすべてのインスタンスのプロパティはRestModel「foo」になります。
  2. それだけでなく、すべての RestModelインスタンスがプロパティ内の同じ配列の同じインスタンスを共有しthis.arrayます。のインスタンスをModel直接作成すると、インスタンスごとに配列の新しいインスタンスが作成されます。
  3. myModel.constructorModel代わりにRestModel。これは、に等しいを含むprototypeの新しいインスタンスでオーバーライドするためです。ModelconstructorModel
  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);

コンストラクターとして使用したくない場合は、次prototypeのようにすることができます。functionObject.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();

その場合、基本的にコンストラクターを模倣します。に渡すこともできますがdescriptorObject.createドキュメントを参照、より冗長になります。ほとんどの人は、ある種のextend関数またはメソッドを使用します(Backboneの例でおそらく見たように)。

それが役に立てば幸い!

于 2012-06-05T14:14:18.280 に答える