使用RequireJS,我怎么传入全局对象或单身呢?
假设我在主页面编写代码,2个依赖关系需要一个对象的同一个实例,并且声明这个依赖关系。 什么是适当的方式去做这个?
基本上我想要做的就是说:“如果这个依赖没有被加载,那么加载它,否则,使用已经加载的同一个实例,并且只传递那个。”
你会做一个模块级别的variables。 例如,
// 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"); };
只要为您的单身人士提供一个API即可。
并确保它的延迟加载。 最简单的方法是使用提供跨浏览器助手的下划线等抽象库。 其他选项是ES5 Object.defineProperty或自定义getter / setter。
在这种情况下, _.once
确保构造函数的结果在第一次调用后被caching,它基本上懒加载它。
define(function() { var constructor = _.once(function() { ... }); return { doStuffWithSingleton: function() { constructor().doStuff(); } }; });
_.once
从下划线。
将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提供的一个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 }; });
由于您notify
使用模块的所有人公开了相同的notify
和listen
方法,并且这些方法始终引用相同的私有 listenerMap
variables,因此应该按照您的要求进行操作。 它也避免了对Function.prototype.bind
的需求,并且消除了消息服务本身和强制使用它的单独模块之间的相当不必要的区别。
这是一个版本,其中模块本身是共享variables,而不是模块内的variables。
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
作为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); });
为了解决下面的评论,我个人发现上面的惯例是有用的。 你的里程可能会有所不同,但如果你觉得有用的话,可以随意采用这个惯例。 大会归结为这两个规则:
- 声明“exports”作为define数组中的第一个依赖项。
- 在JavaScript文件之后命名函数中的参数。
使用文件名(例如foo.js)命名variables“foo”,增加了代码的可读性,因为大多数开发人员将foo定义为foo.js依赖项的参数。 当扫描代码或使用grep时,可以很容易地find在模块内部和外部使用的所有对“foo”的引用,并且可以很容易地找出模块暴露给公众的内容。 例如,如果bar.js模块中的声明反映了其他文件中的用法, bar.setBarOnFoo
bar.setFooBar
重命名为bar.setFooBar
会容易得多。 在所有文件中简单地search并replacebar.setBarOnFoo到bar.setFooBar将完成任务。
我在这种情况下:
由于不同的原因,我需要调用一个在requirejs模块上的函数,但是发起这个调用的点击超出了要求。
我解决这个问题的方法是创build一个写入窗口对象的requirejs模式。
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();
这样,如果任何超出要求频谱的代码(我知道它不应该这样)可以调用这个要求写在窗口对象上的函数。
我真的知道这不是一个“优雅”的解决scheme,但它可以帮助你在紧急情况下。