2

私は他の誰かのJavaScriptコードをリファクタリングしています。

前:

function SomeObj(flag) {
    var _private = true;
    this.flag = (flag) ? true : false;
    this.version="1.1 (prototype)";
    if (!this._someProperty) this._init();
            // leading underscore hints at what should be a 'private' to me
    this.reset(); // assumes reset has been added...
}

SomeObj.prototype.reset = function() {
    /* perform some actions */
}

/* UPDATE */
SomeObj.prototype.getPrivate = function() {
    return _private; // will return undefined
}

/* ...several other functions appended via `prototype`...*/

後:

var SomeObj = function (flag) {
    var _private = true;
    this.flag = (flag) ? true : false;
    this.version = "2.0 (constructor)";

    this.reset = function () {
       /* perform some actions */
    };

    /* UPDATE */
    this.getPrivate = function() {
        return _private; // will return true
    }

    /* other functions and function calls here */
}

私にとって、最初の例は、特により大きな文脈では、読みにくいように見えます。resetプロパティを使用してこのようなメソッドを追加するとprototype、おそらくスクリプトのどこでも発生する可能性があるため、制御がはるかに少ないように見えます。私のリファクタリングされたコード(上記の2番目の例)は、私には非常に見栄えがよく、自己完結型であるため読みやすくなっています。変数宣言である程度のプライバシーを確​​保しましたが、プロトタイプチェーンの可能性を失いました。

..。

質問:

  1. prototypeまず、前述の方法で他に何を失ったのか、またはプロトタイプチェーンの損失に大きな影響があるのか​​どうかを知りたいと思います。この記事は6年前のものですが、prototypeプロパティの使用はクロージャパターンよりも大規模ではるかに効率的であると主張しています。

  2. 上記の両方の例は、引き続きnewオペレーターによってインスタンス化されます。どちらも「古典的な」コンストラクターです。最終的には、これからすべてのプロパティと関数がsとして宣言されているモデルに移行したいと思います。またvar、必要なすべてのプロパティとメソッドを開くオブジェクトを返すことができる1つのメソッドを公開しています。プライベートなものへの特権(閉鎖による)。このようなもの:

    var SomeObj = (function () {
    
        /* all the stuff mentioned above, declared as 'private' `var`s */
    
        /* UPDATE */
        var getPrivate = function () {
            return private;
        }
    
        var expose = function (flag) {
             // just returns `flag` for now
             // but could expose other properties
             return {
                 flag: flag || false, // flag from argument, or default value
                 getPrivate: getPrivate
             } 
        };
    
        return {
            expose: expose
        }
    })(); // IIFE
    
    // instead of having to write `var whatever = new SomeObj(true);` use...
    var whatever = SomeObj.expose();
    

    StackOverflowには、「プロトタイプとクロージャー」の質問に対処するためのいくつかの回答があります(たとえば、ここここ)。しかし、prototypeプロパティと同様に、これに近づき、オペレーターから離れるnewことが、コードの効率と可能性の喪失(たとえばinstanceof、失われる)にとって何を意味するのかに興味があります。newとにかくプロトタイプの継承を使用しない場合、演算子を先に進めることで実際に何かを失うことはありますか?

  3. prototype上記の詳細を求めていることを考えると、許可されている場合はより緩い質問です。new閉鎖よりも多くの利点(あなたが考えているものは何でも)を備えた最も効率的な方法であるかどうか、ガイドラインやデザインはありますか?きちんとした方法でそれらを書くためのパターン?

..。

アップデート:

exposeは毎回新しいオブジェクトを返すので、ここでインスタンス化が発生することに注意してください。私が理解しているように、そのオブジェクトがSomeObjクロージャーで宣言されたメソッドを参照している場合、それらはすべてのオブジェクトで同じメソッドです(上書きされない限り)。flag変数(これを修正しました)の場合、これはの引数から継承するexposeか、デフォルト値を設定するか、カプセル化された既存のメソッドまたはプロパティを再度参照することができます。したがって、オブジェクトが生成されるインスタンスがあり、ここでいくつかの継承(およびポリモーフィズム?)が行われています。

new質問2を繰り返します。とにかくプロトタイプの継承を使用しない場合、演算子を先に進めることで実際に何かを失うのでしょうか。

これまでの回答に感謝します。これは私の質問を明確にするのに役立ちました。

4

4 に答える 4

1

私の経験では、使用しないことで失うの.prototypeはメモリだけです。各オブジェクトは、そこで定義されている関数オブジェクトの独自のコピーを所有することになります。

「少数」のオブジェクトをインスタンス化することだけを目的としている場合、これは大きな問題にはなりません。

あなたの特定の質問に関して:

  1. そのリンクされた記事の2番目のコメントは非常に関連性があります。著者のベンチマークは間違っています。これは、 4つの内部関数も宣言するコンストラクターを実行するオーバーヘッドをテストしています。これらの機能のその後のパフォーマンスはテストしていません。

  2. 「クロージャと公開」のコードサンプルはOOではなく、いくつかの囲まれたプライベート変数を持つ単なる名前空間です。new使用しないので、オブジェクトをインスタンス化する場合は使用しません。

  3. 私はこれに答えることができません-「それは依存します」はあなたがこれのために得ることができるのと同じくらい良い答えです。

于 2013-02-15T12:51:03.123 に答える
1

前述のことで他に何を失ったのprototypeですか?

誰かが答えを出すことができると確信していますが、少なくともそれを試してみます。使用する理由は少なくとも2つありますprototype

  1. prototypeメソッドは静的に使用できます
  2. それらは一度だけ作成されます

オブジェクトメンバーとしてメソッドを作成するということは、オブジェクトのすべてのインスタンスに対してメソッドが作成されることを意味します。これはオブジェクトあたりのメモリが多く、オブジェクトの作成が遅くなります(したがって効率が低下します)。prototypeメソッドはクラスメソッドに似ているのに対し、メンバーメソッドはオブジェクトメソッドに似ているとよく言われますが、プロトタイプチェーンのメソッドは引き続きオブジェクトインスタンスを使用できるため、これは非常に誤解を招く恐れがあります。

プロトタイプをオブジェクト自体として定義できるので、構文の方が好きかもしれません(ただし、それほど違いはありません)。

SomeObj.prototype = {
    method1: function () {},
    method2: function () {}
}

あまり制御されていないように見えるというあなたの議論は私には有効です。オブジェクトの作成に2つのブロックが関係しているのは奇妙だと思います。ただし、とにかく誰かが他のオブジェクトのプロトタイプを上書きするのを妨げるものは何もないという点で、少し不思議です。

//Your code
var SomeObj = function (flag) { //...

//Sneaky person's code
delete SomeObj.reset;
SomeObj.prototype.reset = function () { /* what now? */ }

先送りnew

表記法を使用してその場で特定のオブジェクトインスタンスを作成するだけの場合は、とにかく{}使用するのと実際には違いはありませんnew。クラス( )定義newから同じオブジェクトの複数のインスタンスを作成するためにを使用する必要があります。functionこれは、オブジェクト指向プログラミング言語に適用されるため、珍しいことではなく、再利用に関係しています。

現在のアプリケーションでは、これはうまくいく可能性があります。ただし、コンテキスト間で再利用可能な素晴らしいプラグインを思いついた場合は、それを何度も書き直さなければならないのは面倒になる可能性があります。require.js関数でインポートできる「モジュール」を定義できる、のようなものを探していると思いますrequire。関数クロージャ内でモジュールを定義するdefineので、とにかくコンストラクタとプロトタイプの定義をまとめておくことができ、そのモジュールをインポートするまで、他の誰もそれらに触れることはできません。

クロージャとの利点prototype

それらは相互に排他的ではありません:

var attachTo = {};
;(function (attachTo, window, document, undefined) {
    Plugin = function () { /* constructor */ };
    Plugin.prototype = { /* prototype methods */ };

    attachTo.plugin = Plugin;
})(attachTo, window, document);
var plugin = new (attachTo.plugin);

http://jsfiddle.net/ExplosionPIlls/HPjV7/1/

于 2013-02-15T13:00:36.200 に答える
1

答え:

  1. あなたはすでにこの質問に答えています:プロトタイプ チェーンを緩めます。(実際には失うことはありませんが、プロトタイプは常に空になります)。結果は次のとおりです。

    • インスタンスごとにメソッドが作成されるため、パフォーマンスやメモリに多少の影響があります。ただし、これは JavaScript エンジンに大きく依存するため、大量のオブジェクトを作成する必要がある場合にのみ心配する必要があります。

    • プロトタイプを変更してパッチ インスタンスをモンキーすることはできません。それを行うとメンテナンスの悪夢につながるため、大きな問題でもありません。

  2. あなたの質問に少し衒学的な修正を加えさせてください。「プロトタイプとクロージャー」の問題ではありません。実際、クロージャーの概念はプロトタイプベースの言語と直交しています。

    問題は、オブジェクトを作成する方法に関連しています。毎回ゼロから新しいオブジェクトを定義するか、プロトタイプから複製します。

    関数を使用してスコープを制限する方法について示した例は、JavaScript での通常のプラクティスであり、プロトタイプを使用することにした場合でも、それを続けることができます。例えば:

    var SomeObj = (function (flag) {
    
        /* all the stuff mentioned above, declared as 'private' `var`s */
    
        var MyObj = function() {}
        MyObj.prototype = {
            flag: flag,
            reset: reset
        };
    
        return {
           expose: function() { return new MyObj(); }
        }
    })();
    

    モジュール化に不安がある場合は、AMD(非同期モジュール定義)という手法の実装であるrequirejsを調べてみてください。AMDが嫌いな人もいれば、好きな人もいます。私の経験はポジティブなものでした。ブラウザ用のモジュール式 JavaScript アプリを作成するのに大いに役立ちました。

  3. プロトタイプを簡単に作成できるライブラリがいくつかあります: composejsdejavu、および私のバーマン(はい、恥知らずな自己宣伝ですが、ソース コードを調べて、オブジェクトの定義を処理する方法を確認できます)。

    パターンについて:ファクトリ メソッドを使用してオブジェクトのインスタンス化を簡単に隠すことができるためnew、プロトタイプを内部的に複製するために使用できます。

于 2013-02-15T14:29:04.700 に答える
0

質問ごと:

  1. 基本的に、コンストラクターのすべてのインスタンスがresetメソッドprototypeのまったく同じコピーを共有することを意味します。コンストラクター内でローカル メソッドを作成すると、インスタンスごとにメソッドのコピーが 1 つ作成され、より多くのメモリが消費されます (インスタンスが多数ある場合は、これが問題になる可能性があります)。それ以外は、両方のバージョンは同じです。function SomeObjへの変更は、親スコープでの巻き上げvar SomeObj = function方法のみが異なります。SomeObjあなたは「変数宣言である程度のプライバシーを獲得した」と言っていましたが、そこにはプライベート変数は見られませんでした...

  2. あなたが言及したIIFEアプローチでは、チェックする能力が失われますinstance instanceof SomeObj.

  3. これがあなたの質問に答えるかどうかはわかりませんが、プロトタイプを設定できますが、キーワードObject.createを取り除くこともできます。newただし、コンストラクターを持つ機能は失われます。

于 2013-02-15T12:54:05.713 に答える