Używając RequireJS, Jak mogę przejść w obiektach globalnych lub singletonach?

Załóżmy, że piszę kod na poziomie strony głównej i 2 zależności wymagają tej samej instancji obiektu, a także stwierdzają to jako zależność. Jaki jest odpowiedni sposób, aby to zrobić?

Zasadniczo chcę powiedzieć: "jeśli ta zależność nie jest załadowana... więc załaduj. W przeciwnym razie użyj tej samej instancji, która została już załadowana i po prostu ją przekaż."

Author: egervari, 2011-04-10

6 answers

Zrobiłbyś z tego zmienną na poziomie modułu. Na przykład,

// 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");
};
 59
Author: Domenic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-09 23:59:51

Po prostu podaj API dla Twojego Singletona, tak jak byś chciał.

I upewnij się, że jest leniwie naładowany. Najprostszym sposobem jest użycie biblioteki abstrakcji, takiej jak podkreślenie, która dostarcza pomocników między przeglądarkami. Inne opcje to obiekt ES5.defineProperty lub custom getter / setters.

W tym przypadku _.once zapewnia, że wynik konstruktora jest buforowany po pierwszym wywołaniu, zasadniczo ładuje go leniwie.

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

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

});

_.once z podkreślenia.

 8
Author: Raynos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-10 00:24:52

Łącząc obawy Raynosa o enkapsulację z wyjaśnieniem OP, że chce ujawnić kilka metod na komunikatorze, myślę, że jest to właściwy sposób, aby to zrobić: {]}

// 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 nie będzie obecny we wszystkich przeglądarkach, więc trzeba będzie dołączyć polyfill jak Ten, który Mozilla dostarcza.

Alternatywnym (i moim zdaniem chyba lepszym) podejściem byłoby uczynienie samego obiektu messaging service modułem. To by wyglądało na coś jak

// 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
    };
});

Ponieważ ujawniasz te same metody notify i listen wszystkim, którzy używają Twojego modułu, a te zawsze odnoszą się do tych samych {16]} prywatnych listenerMap zmienna, to powinno zrobić to, co chcesz. Eliminuje również potrzebę Function.prototype.bind i pozbawia się raczej niepotrzebnego rozróżnienia pomiędzy samą usługą przesyłania wiadomości a modułem wymuszającym użycie Singletona.

 6
Author: Domenic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-10 03:28:59

Oto wersja, w której sam moduł jest zmienną współdzieloną, a nie zmienną wewnątrz tego modułu.

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
 1
Author: Benny Bottema,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-10 09:19:29

Jako odmiana odpowiedzi Domenica, możesz użyć magicznego modułu 'exports' , aby automatycznie wygenerować referencję dla modułu -- " właściwości dodane do obiektu exports będą w publicznym interfejsie modułu, nie ma potrzeby zwracania żadnej wartości."Pozwala to uniknąć konieczności wywoływania funkcji getTheFoo() w celu uzyskania referencji.

// 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);
});

Aby odnieść się do poniższego komentarza, osobiście uznałem powyższą konwencję za przydatną. Przebieg może się różnić, ale nie wahaj się przyjąć konwencja, jeśli uważasz, że jest przydatna. Konwencja sprowadza się do tych dwóch zasad:

  • Zadeklaruj 'exports' jako pierwszą zależność w tablicy define.
  • Nazwij parametr funkcji po pliku JavaScript.

Używając nazwy pliku, np. dla foo.js nazywa zmienną "foo", zwiększa czytelność kodu, ponieważ większość programistów zdefiniuje " foo " jako parametr dla foo.zależność od js. Podczas skanowania kodu lub korzystania z grep, łatwo jest Znajdź wszystkie odniesienia do " foo " używaj zarówno wewnątrz, jak i na zewnątrz modułu, dzięki czemu łatwo jest wybrać, co moduł wystawia na widok publiczny. Na przykład zmiana nazwy bar.setBarOnFoo na bar.setFooBar jest znacznie łatwiejsza, jeśli deklaracja w pasku.moduł js odzwierciedla użycie w innych plikach. Proste wyszukiwanie i wymiana paska.setBarOnFoo to bar.setFooBar we wszystkich plikach wykona zadanie.

 0
Author: Eric Bronnimann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-03 21:00:33

Byłem w tym scenariuszu:

Z różnych powodów musiałem wywołać funkcję, która była w module requirejs, ale kliknięcie, które wywołało to połączenie, nie było wymagane.

Sposób, w jaki to naprawiłem, polegał na tworzeniu modury wymagajs, która zapisuje nad obiektem window.

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

W ten sposób, jeśli jakikolwiek fragment kodu, który jest poza spektrum require (wiem, że nie powinno tak być) może wywoływać funkcje tego require, które zapisują się nad obiektem window.

Naprawdę to wiem nie jest" eleganckim " rozwiązaniem, ale może Ci pomóc w nagłych wypadkach.

 -1
Author: Sanchitos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-01 19:34:20