我即将开始构建一个包含多个模块的JS库。假设库名为Library,两个模块称为One和Two。我希望最终用户能够以两种不同的方式调用库:
Library.One.somefunction(params)
或
somefunction(params)
基本上,我想让最终用户选择是否包含命名空间。有没有办法做到这一点?另外,如果我还想提供缩小版本的库,有没有一种好方法可以做到这一点?我可以在Node.js中找到这个库;现在,我将自己使用它,但我想以这样一种方式设计它,以便将来转向一个可共享的项目并不太难。
你可以指出我的任何参考资料都很棒,谢谢!
答案 0 :(得分:5)
如果您使用的是 Node.js ,则可以使用 CommonJS 模块系统。
math.js (您的图书馆)
exports.add = function() {
for (var i = arguments.length; i--;) {
sum += arguments[i];
}
return sum;
};
program.js (有人使用它......)
var MyMath = require('math');
console.log(MyMath.add(1, 2)); // 3
// ... in different ways
var add = require('math').add;
console.log(add(1, 2)); // 3
答案 1 :(得分:2)
使“命名空间”可选的基本思想是将函数分配给全局范围,即window
对象:
window.somefunction = Library.One.somefunction;
您可以编写与其他语言类似的include
函数:
var include = function (library, p) {
if (!p) {
for (var prop in library) {
if (library.hasOwnProperty(prop)) {
window[prop] = library[prop];
}
}
} else {
window[p] = library[p];
}
};
然后根据需要做:
include(Library.One);
或仅使用特定功能:
include(Library.One, 'somefunction');
<强>警告强>:
执行不带点符号(One.somefunction
)的函数将导致this
关键字引用window
而不是Library.One
。如果您根本不使用this
,这不是问题。如果要在函数之间共享数据,那么可以使用闭包范围而不是this
:
var Library = {};
(function () {
// I'm a closure, I have local scope
var sharedData = "I'm shared but private to this scope";
Library.One = {};
Library.One.funcOne = function () {
alert(sharedData);
};
Library.One.funcTwo = function () {
sharedData += "!";
};
}) ();
其他人建议不要让你的方法全局化。这是因为一旦它是全局的,它对所有文件都是全局的,因此可能与其他代码冲突。您可以做的是修改上面的import
函数来创建一个新对象,并在返回之前将所有内容分配给该对象。然后需要快捷方式到特定库的文件可以:
(function () {
var _ = include(Library.One); // This stays within this scope
_.somefunction();
})();
答案 2 :(得分:1)
for(var i in Namespace) if(Namespace.hasOwnProperty(i)) window[i] = Namespace[i];
答案 3 :(得分:0)
您可以非常轻松地完成此操作,但是您确定要将所有方法设为全局属性吗?
您可以像这样(非常简化)实现它:
(function( window, undefined ) {
// Your code setting up namespaces
var Library = {One:{},Two:{}};
// function for adding library code to both namespaces.
// Could be modified to accept an Array of functions/names
function addToLibraryOne( id, fn ) {
window[id] = Library.One[id] = fn;
}
// add a function
addToLibraryOne( "somefunction", function( params ) {
// function code
});
window.Library = Library;
})( window );
我想知道你是否真的想污染像这样的全局命名空间。
至少,我会将global
属性设为选项,然后只有选中该选项时才添加该功能。
答案 4 :(得分:0)
我可能错了(所以这可能会被低估,但我希望这个被评估),但我认为你正在设置与要求的矛盾
1)我想使用命名空间
2)我希望能够在没有命名空间的情况下访问命名空间功能。
基本上2是“我不想要名称空间”。
对于实现,您可以在全局中定义一系列路由到命名空间的函数,但为什么要以命名空间开头呢?
答案 5 :(得分:0)
嗯,第二个意味着您还希望函数和对象以及模块中的任何内容都在全局范围内。当然完全可能,但最好的做法是有点令人憎恶。
对于第一部分,只需全局声明您的Library命名空间:
var Library = {};
然后开始使用您的模块填充它:
Library.One = {};
Library.Two = {};
然后开始向这些模块添加功能。
(function($) {
var $.froobString = function(s) { .... };
...etc...
})(Library.One);
(这里我把它作为一个自动执行的匿名函数,将Library.One
作为$
传递。)
要将所有内容转换为全局变量,请使用以下例程:
var convertToGlobals = function(module) {
for (name in module) {
window[name] = module[name];
}
};
convertToGlobals(Library.One)
但是我再次建议反对它。