1

私は確かにJavaScriptの内部の仕組みについてほとんど知りませんが、ライブラリを作成する必要があり、学びたいと思っています(したがって、ここで質問しています)。グローバル名前空間を汚染しないようにクロージャーとウィンドウへのエクスポートを使用することは理解していますが、それ以上は少し混乱します。

(function() {
    var Drop = window.Drop = function() { 

        var files = [];

        var add = function(word) {
              files.push(word);    
              return files;
        }

        return {
            files: files,
            add: add
        }
    }
})()


// All of these seem to be the same?
var a = Drop();
var b = new Drop();
var c = new Drop;

// Each has their own state which is what I want.
a.add("file1");
b.add("file2");
c.add("file3");
  • Drop を「初期化」する 3 つの方法がすべて同じなのはなぜですか?
  • 彼らに独自の状態を持つ能力を正確に与えるものは何ですか?
  • Drop でこれらの関数をエクスポートするための return 構文に代わるものはありますか?
  • このような自己完結型ライブラリを作成するための、より優れたベストプラクティスの方法はありますか?

私はネットを検索しましたが、この件に関してほとんど一貫性がありませんでした.

4

2 に答える 2

2
  1. 最初の方法 ( Drop()) は通常どおり関数を呼び出すだけでthis、グローバル オブジェクト (windowブラウザー環境) も同様です。ご想像のとおり、処理を実行してからオブジェクトを返します。

    2 番目の方法 ( new Drop()) は、新しいオブジェクトを作成し、そのオブジェクトを設定してDropコンストラクターを実行します。thisただし、thisどこでも使用せず、オブジェクト リテラルから作成されたオブジェクトを返すため、Dropオブジェクトは破棄され、代わりにオブジェクト リテラルが返されます。

    3 番目の方法 ( new Drop) は意味的には 2 番目の方法と同じです。構文上の違いにすぎません。

  2. を呼び出すたびDropに、他のDrop.

  3. new通常の構文とプロトタイプを使用するようにコードを変換できます。これにはいくつかの利点があります。つまり、関数を呼び出しaddごとに作成するのではなく、1 回だけ作成します。Drop変更したコードは次のようになります。

    function Drop() {
        this.files = [];
    }
    Drop.prototype.add = function(word) {
        this.files.push(word);
        return this.files;
    };
    

    ただし、これを行うと、 なしで呼び出すことができなくなりnewます。ただし、回避策があります。これを 内の最初の行として追加できますfunction Drop

    if(!(this instanceof Drop)) {
        return new Drop();
    }
    

    で呼び出すと にnewなりthisDropなしnewで呼び出すとthis以外になるので、 が であるかDropどうかを確認thisDrop、そうであれば初期化を続行します。それ以外の場合は、で再呼び出ししnewます。

    もう 1 つの意味上の違いもあります。次のコードを検討してください。

    var drop = new Drop();
    var adder = drop.add;
    adder(someFile);
    

    あなたのコードはここで動作します。プロトタイプ ベースのコードは、thisではなくグローバル オブジェクトになるため、そうではありませんdrop。これにも回避策があります。コンストラクターのどこかで、これを行うことができます。

    this.add = this.add.bind(this);
    

    もちろん、ライブラリのコンシューマーがオブジェクトから関数を引き出すつもりがない場合は、これを行う必要はありません。Function.prototype.bindさらに、シムがないブラウザではシムが必要になる場合があります。

  4. いいえ、それはすべて好みの問題です。

于 2013-02-09T23:09:08.100 に答える
1
  • Drop を「初期化」する 3 つの方法がすべて同じなのはなぜですか?

// All of these seem to be the same?
var a = Drop();
var b = new Drop();
var c = new Drop;

new関数を呼び出すために JavaScript で を使用するthisと、関数内の の値が新しいオブジェクトになります。

しかし、あなたのケースでそれらが同じである理由は、まったく使用thisしていないからです。オブジェクト リテラル構文を使用して別のオブジェクトを作成し、代わりにそれを返すため、new影響はありません。


  • 彼らに独自の状態を持つ能力を正確に与えるものは何ですか?

関数呼び出しごとに新しいオブジェクトが作成されるため、各オブジェクトは呼び出しごとにまったく異なります。

オブジェクトに割り当てられた関数は呼び出しごとに再作成されるDropため、囲んでいる変数スコープにクロージャーが作成されます。そのため、files各呼び出しの配列は、それぞれの呼び出しで作成された関数に継続的にアクセスできます。


  • Drop でこれらの関数をエクスポートするための return 構文に代わるものはありますか?

はい。関数と配列を に割り当て、ステートメントthisを削除します。returnしかし、それnew. または、関数を の.prototypeオブジェクトに配置するDropと、 を使用して作成されたすべてのインスタンス間で共有されますが、共有されないように、コンストラクターでnew割り当てられた配列を保持します。this

プロトタイプ化された関数が配列を参照するには、this.files.


  • このような自己完結型ライブラリを作成するための、より優れたベストプラクティスの方法はありますか?

JavaScript は非常に柔軟です。1 つの問題にアプローチする方法は多数あり、それぞれに長所と短所があります。一般的には、クロージャープロトタイプの継承、または両方の組み合わせを利用することになります。


これは、完全なプロトタイプの継承バージョンです。また、outer(function() {})()は使用されていないので、それを利用するために変数を追加します。

(function() {
    var totalObjects = 0; // visible only to functions created in this scope

    var Drop = window.Drop = function() { 
        this.files = [];
        this.serialNumber = totalObjects++;
    }

    Drop.prototype.add = function(word) {
        this.files.push(word);    
        return this.files;
    };
})();
于 2013-02-09T23:11:10.073 に答える