54

私がメインページレベルでコードを書いていて、2つの依存関係がオブジェクトの同じインスタンスを必要とし、それを依存関係として述べているとしましょう。これを行うための適切な方法は何ですか?

基本的に私がやりたいのは、「この依存関係がロードされていない場合は...ロードします。それ以外の場合は、すでにロードされているのと同じインスタンスを使用して、そのインスタンスを渡すだけです」と言います。

4

6 に答える 6

58

これをモジュールレベルの変数にします。例えば、

// In foo.js
define(function () {
    var theFoo = {};

    return {
        getTheFoo: function () { return theFoo; }
    };
});

// In bar.js
define(["./foo"], function (foo) {
    var theFoo = foo.getTheFoo(); // save in convenience variable

    return {
        setBarOnFoo: function () { theFoo.bar = "hello"; }
    };
}

// In baz.js
define(["./foo"], function (foo) {
    // Or use directly.
    return {
        setBazOnFoo: function () { foo.getTheFoo().baz = "goodbye"; }
    };
}

// In any other file
define(["./foo", "./bar", "./baz"], function (foo, bar, baz) {
    bar.setBarOnFoo();
    baz.setBazOnFoo();

    assert(foo.getTheFoo().bar === "hello");
    assert(foo.getTheFoo().baz === "goodbye");
};
于 2011-04-09T23:54:26.920 に答える
8

シングルトン用のAPIを提供するだけです。

そして、その怠惰なロードを確認してください。最も簡単な方法は、クロスブラウザヘルパーを提供するアンダースコアのような抽象化ライブラリを使用することです。その他のオプションは、ES5Object.definePropertyまたはカスタムゲッター/セッターです。

この場合_.once、コンストラクターの結果が最初の呼び出しの後にキャッシュされることを保証し、基本的にレイジーロードします。

define(function() {
    var constructor = _.once(function() { 
        ...
    });

    return {
        doStuffWithSingleton: function() {
            constructor().doStuff();
        }
    };

});

_.onceアンダースコアから。

于 2011-04-10T00:18:02.243 に答える
6

カプセル化に関するRaynosの懸念と、メッセージングサービスでいくつかのメソッドを公開したいというOPの明確化を組み合わせると、これは正しい方法だと思います。

// In messagingServiceSingleton.js
define(function () {
    var messagingService = new MessagingService();

    return {
        notify: messagingService.listen.bind(messagingService),
        listen: messagingService.notify.bind(messagingService)
    };
});

// In bar.js
define(["./messagingServiceSingleton"], function (messagingServiceSingleton) {
    messagingServiceSingleton.listen(/* whatever */);
}

// In baz.js
define(["./messagingServiceSingleton"], function (messagingServiceSingleton) {
    messagingServiceSingleton.notify(/* whatever */);
}

Function.prototype.bindすべてのブラウザに表示されるわけではないため、Mozillaが提供するようなポリフィルを含める必要があります。

別の(そして私の意見ではおそらくより良い)アプローチは、メッセージングサービスオブジェクト自体をモジュールにすることです。これは次のようになります

// In messagingService.js
define(function () {
    var listenerMap = {};

    function listen(/* params */) {
        // Modify listenerMap as appropriate according to params.
    }
    function notify(/* params */) {
        // Use listenerMap as appropriate according to params.
    }

    return {
        notify: notify
        listen: listen
    };
});

notifyモジュールを使用するすべての人に同じメソッドとメソッドを公開しlisten、それらは常に同じプライベート listenerMap変数を参照するため、これで必要な処理を実行できます。また、の必要性をFunction.prototype.bind排除し、メッセージングサービス自体とそれのシングルトン使用を強制するモジュールとの間のかなり不必要な区別を取り除きます。

于 2011-04-10T03:28:59.150 に答える
1

これは、モジュール自体がそのモジュール内の変数ではなく共有変数であるバージョンです。

define('foo', [], {bar: "this text will be overwritten"});

define('bar', ["foo"], function (foo) {
    return {
        setBarOnFoo: function () { foo.bar = "hello"; }
    };
});

define('baz', ["foo"], function (foo) {
    return {
        setBazOnFoo: function () { foo.baz = "goodbye"; }
    };
});

require(["foo", "bar", "baz"], function (foo, bar, baz) {
    bar.setBarOnFoo();
    baz.setBazOnFoo();

    $('#results').append(foo.bar + ' ' + foo.baz);
});​​​

// reads: hello goodbye
于 2012-07-23T10:19:44.383 に答える
0

Domenicの回答のバリエーションとして、「exports」マジックモジュールを使用して、モジュールの参照を自動的に生成できます。「exportsオブジェクトに追加されたプロパティは、モジュールのパブリックインターフェイスにあり、値を返す必要はありません。 「」getTheFoo()これにより、参照を取得するために関数を呼び出す必要がなくなります。

// In foo.js
define(['exports'], function (foo) {
   foo.thereCanBeOnlyOne = true; 
});

// In bar.js
define(["exports", "./foo"], function (bar, foo) {
  bar.setBarOnFoo = function () { foo.bar = "hello"; };
});

// in baz.js
define(["exports", "./foo"], function (baz, foo) {
  baz.setBazOnFoo = function () { foo.baz = "goodbye"; };
});

// In any other file
define(["./foo", "./bar", "./baz"], function (foo, bar, baz) {
  bar.setBarOnFoo();
  baz.setBazOnFoo();

  assert(foo.bar === "hello");
  assert(foo.baz === "goodbye");
  assert(foo.thereCanBeOnlyeOne);
});

以下のコメントに対処するために、私は個人的に上記の規則が有用であると感じました。マイレージは異なる場合がありますが、便利だと思われる場合は、この規則を自由に採用してください。規則は、次の2つのルールに要約されます。

  • 定義配列の最初の依存関係として「エクスポート」を宣言します。
  • JavaScriptファイルにちなんで関数内のパラメーターに名前を付けます。

ファイル名を使用すると、たとえばfoo.jsの名前に変数「foo」を使用すると、ほとんどの開発者がfoo.js依存関係のパラメーターとして「foo」を定義するため、コードの可読性が向上します。コードをスキャンしたり、grepを使用したりする場合、モジュールの内部と外部の両方で使用されている「foo」へのすべての参照を簡単に見つけることができ、モジュールが公開しているものを簡単に見つけることができます。たとえば、bar.jsモジュールの宣言が他のファイルの使用法を反映している場合、名前の変更ははるかに簡単ですbar.setBarOnFoobar.setFooBarすべてのファイルでbar.setBarOnFooをbar.setFooBarに検索して置き換えるだけで、タスクを実行できます。

于 2016-02-03T07:02:37.163 に答える
-1

私はこのシナリオにいました:

さまざまな理由で、requirejsモジュール上にある関数を呼び出す必要がありましたが、その呼び出しを起動したクリックは必要外でした。

これを修正する方法は、ウィンドウオブジェクトを上書きするrequirejsmodureを作成することでした。

define("one", [], function() {
    window.popupManager = (function () {
            console.log ('aca');

        var popUpManager = function () {
            self = this;

            self.CallMe = function ()
            {
                alert ('someone calls');
            };
        };
        return new popUpManager();
    })();
});
require(['one']);

window.popupManager.CallMe();

このようにして、requireスペクトルの外にあるコードの一部(このようにすべきではないことを私は知っています)がこのrequireの関数を呼び出すことができる場合、ウィンドウオブジェクトを上書きします。

私はこれが「エレガントな」解決策ではないことを本当に知っていますが、緊急の場合に役立つかもしれません。

于 2016-02-01T19:34:20.450 に答える