为了澄清,请考虑以下简化示例:
one.js
Components.utils.import('resource://gre/modules/Services.jsm');
let obj = {
init: function() {
Components.utils.import('chrome://myaddon/modules/two.jsm', this);
}
// code here has access to Services.jsm
}
two.js
this.EXPORTED_SYMBOLS = ['abc'];
this.abc = {
// abc is imported into obj()
// however as part of obj (), abc{} does not have access to Services.jsm
}
我知道这是它的工作方式,但问题是为什么?
结果是,例如Services.jsm
必须在每个模块中传授
虽然Firefox缓存模块并且没有太大的性能差异,但我想知道是否可以避免重复输入?
答案 0 :(得分:2)
就像已经提到的@ felix-kling一样,这是由于模块级别的隔离,如果你考虑它会很有意义。如果不是这样,其他模块不仅会Services
,还会abc
。
但还有另一个重要原因:
由于JS代码模块一次启动并在此之后进行缓存,如果您导入two.jsm
两次,一次从已导入Services.jsm
的模块导入,另一次从另一个模块导入{1}},会发生什么?现在two.jsm
“看到”Services
将取决于首先导入的其他模块!这将是非常讨厌的。
在这种情况下,您对“abc导入obj()”的评论是错误的。您的代码实际上将abc
导入顶级范围。 Cu.import
将始终导入顶级范围,除非您明确指定要导入的另一个范围。
"abc" in this; // false
"abc" in obj; // false
obj.init();
"abc" in this; // true
"abc" in obj; // false!
如果您想将two.jsm
导入obj
,则需要使用第二个参数调用Cu.import
。
let obj = {
init: function() {
Components.utils.import('chrome://myaddon/modules/two.jsm', this);
}
};
"abc" in this; // false
"abc" in obj; // false
obj.init();
"abc" in this; // false
"abc" in obj; // true
但这当然不会影响Services
的可见性。
我想,如果Cu.import
只是自动导入了您要导入的某些模块,例如Services.jsm
和XPCOMUtils.jsm
,那将会很有帮助。但由于遗留原因和向后兼容性限制,这不会也不会发生。 (例如,我有导入const {Promise} = Cu.import(..., {});
的代码中断,因为ES6添加了一个默认的Promise
全局...;这种向后兼容性问题/约束。)
嗯,显而易见的是不要将Cu.import
用于自己的东西,而是使用别的东西。一堆附加组件,包括当然,所有SDK加载项都有自己的CommonJS样式require()
实现。
loader
文档。我知道Erik在另一个非SDK Scriptish插件中创建了一个加载器。Sandbox
。例如。我在extSDK
样板文件中这样做了(每个== loader.jsm::exports
d模块都可以看到loader.jsm require
中的所有全局符号。)但这样做可能需要额外的工作,额外的知识和努力将现有的JS代码模块移植到基于require()
的模块。