使用RequireJS,如何传递全局对象或单例?

ege*_*ari 54 javascript singleton requirejs

假设我在主页面级别编写代码,并且2个依赖项需要对象的相同实例,并且还将其声明为依赖项.适当的方法是什么?

基本上我想要做的就是说,"如果没有加载这个依赖...然后加载它.否则,使用已加载的同一个实例,然后传递那个."

Dom*_*nic 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");
};
Run Code Online (Sandbox Code Playgroud)

  • 此外,它不会污染全局命名空间.它仅适用于那些明确声明`foo`为依赖的模块. (8认同)
  • @Raynos:false; 它正在实现单例模式,这是面向对象编程解决全​​局变量在过程语言中解决的问题的方法. (3认同)

Ray*_*nos 8

只需像您一样为您的单身人士提供API.

并确保它懒洋洋地加载.最简单的方法是使用像下划线那样提供跨浏览器帮助程序的抽象库.其他选项是ES5 Object.defineProperty或自定义getter/setter.

在这种情况下,_.once确保构造函数的结果在第一次调用后被缓存,它基本上是懒惰加载它.

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

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

});
Run Code Online (Sandbox Code Playgroud)

_.once 从下划线.


Dom*_*nic 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 */);
}
Run Code Online (Sandbox Code Playgroud)

Function.prototype.bind将不会出现在所有浏览器中,因此您需要包含像Mozilla提供的那样 polyfill .

备用(在我看来可能更好)的方法是使消息传递服务对象本身成为一个模块.这看起来像

// 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
    };
});
Run Code Online (Sandbox Code Playgroud)

既然你公开相同notifylisten谁使用你的模块的方法给大家,和那些总是指向同一个私有 listenerMap变量,这应该做你想做的.它还消除了Function.prototype.bind对消息传递服务本身和强制单独使用它的模块之间相当不必要的区别的需要和消除.