像Underscore.js和LoDash.js这样的JS库通常通过全局对象_
提供函数:
_.map(...);
_.filter(...);
这些基本函数是Python中的全局函数,也是标准库的一部分:
map(...)
filter(...)
如果我将库函数提升为全局函数......
window.map = _.map;
window.filter = _.filter;
map(...);
filter(...);
......会有什么缺点(全局命名空间污染除外)?
我是否必须期待任何性能问题?
是否会导致某些浏览器出错? (例如,如果内部JS函数被库函数覆盖,而库函数又依赖于本机函数)
链接还能用吗?
答案 0 :(得分:2)
有许多缺点,但性能不太可能是其中之一。
如果两个库具有map()
功能并且行为略有不同怎么办?如果他们都将map()
放在全球空间中,您将无法访问其中一个。而且您可能无法轻易知道您实际想要的map()
已被覆盖。
顺便说一句,map()
和filter()
是最近的JS实现的一部分,但即使在那里,它们也是使用它们的对象原型的一部分。所以你有Array.prototype.map()
和Array.prototype.filter()
。
答案 1 :(得分:2)
以下是避免将map
和filter
等大量内容变为全局变量的一些原因:
命名与尝试执行类似但不兼容的其他代码/库的冲突。如果所有代码都使用了大量的全局函数,那么单个全局函数的简单定义可能会完全破坏你的应用程序,因为它将重新定义用于代码中其他地方的其他东西的函数。这本身就是使用尽可能少的全局变量的原因。在使用重要的第三方库的团队项目或项目中,这是不可能管理的,并且将不可避免地导致生产力损失,或者甚至更糟糕的是,可能不会立即出现的坏错误。
当符号只是全局时,代码模块不太自我描述。嗯,符号map()
来自何处。这是内置的吗?它是在本地定义的吗?它是由某个图书馆定义的吗?知道gutils.map()
来自哪里(来自gutils
模块)要容易得多。大量的全局事物比将事物分解为明确定义的模块更难以维护。
将函数定义为对其运行的对象的方法有很多好处(例如ES5 .map()
和.filter()
是Array对象上的方法而不是通用的全局变量。现在,将非标准方法添加到现有内置对象(也是为了命名冲突原因)被认为是不好的做法,但鼓励添加实现标准行为的polyfill。
有关其他信息,请参阅这些参考资料:
How and Why to Avoid Globals in Javascript
I've Heard Global Variables Are Bad, What Alternative Solution Should I Use?
Essential Javascript Namespacing Patterns
Javascript Namespaces and Modules
How do I declare a namespace in JavaScript?
关于性能主题,它不应该是您的第一个问题,在大多数代码中甚至可能不是相关问题。更重要的是从一个强大的,可维护的编码策略开始,然后只优化性能至关重要的小部分代码,而不是在性能名称的开头牺牲稳健性。
在性能严格的任何紧密循环中,您始终可以将任何函数分配给局部变量以略微提高性能,这将比模块引用或全局引用更快(因为本地化在全局变量之前被解析)。 / p>
因此,如果您在模块中有gUtils.map()
并希望在特定函数中最大化性能,则可以执行以下操作:
function x() {
var map = gUtils.map;
for (var i = 0; i < someBigNumber; i++) {
map(...);
}
}
答案 2 :(得分:1)
您无需担心性能问题;即使您在符号查找中添加了额外的图层,大多数现代JS引擎也会对其进行别名。您也不应该担心增加导致异常的本机对象 - 这是允许的。不,最大的问题是命名空间污染,你似乎对它有点不屑一顾。
当您的代码在本地实现这些功能的较新浏览器上运行时会发生什么?假设您在2009年编写了此代码,并将.map()添加到Array.prototype。如果有人添加了一个期望一个函数签名(本地签名)并且得到另一个(你的)的新库,那么你的代码现在会有一些大问题。
如果必须这样做,至少要检查全局符号是否已存在,例如
window.map = window.map || myLib.map;
此外,请确保依赖于您的地图实现的任何代码都可以将其依赖关系发送到JavaScript依赖关系管理工具(如RequireJS),或者您已经拥有一个强大的DM系统,并且您的本机覆盖在任何之前都已附加其他代码执行(例如,不要将代码放在异步脚本标记中,不要将执行推迟到DOMContentLoaded等)。
答案 3 :(得分:1)
考虑像这样的库,
_ = (function(){
lib = {};
lib.function1 = function(){
//code
};
lib.function2 = function(){
this.function1();
};
//more code
return lib;
})();
如果你使用,
window.function2 = _.function2;
function2();
图书馆使用&#34;这个&#34; function2中的运算符。你的方式在这里改变了function2的范围。 function2()调用将给出错误说&#34; function1未定义&#34;。