全局命名空间中的JavaScript库函数-缺点
JavaScript library functions in global namespace - drawbacks?
像Undercore.JS和LoDash.JS这样的JS库提供函数,通常通过全局对象_
:
_.map(...);
_.filter(...);
这些基本函数是Python中的全局函数,也是标准库的一部分:
map(...)
filter(...)
如果我将库函数提升为全局函数。。。
window.map = _.map;
window.filter = _.filter;
map(...);
filter(...);
会有什么负面影响(除了全局名称空间污染)?
我一定要期待任何性能问题吗?
它会导致某些浏览器出现错误吗?(例如,如果内置JS函数被库函数覆盖,而库函数又依赖于本机函数)
链接仍然有效吗?
有多种缺点,但性能不太可能是其中之一。
如果两个库有一个map()
函数,并且行为略有不同,该怎么办?如果它们都将map()
放在全局空间中,您将无法访问其中一个。而且您可能无法轻易知道您实际想要的map()
已被覆盖。
顺便说一句,map()
和filter()
是最近的ish JS实现的一部分,但即使在那里,它们也是使用它们的对象原型的一部分。所以你有Array.prototype.map()
和Array.prototype.filter()
。
以下是避免将map
和filter
等许多事物作为全局变量的一些原因:
-
命名与其他试图执行类似但不兼容操作的代码/库冲突。如果所有代码都使用了许多全局函数,那么一个全局函数的简单定义可能会完全破坏你的应用程序,因为它会重新定义这样一个函数,用于代码中的其他地方。这本身就是使用尽可能少的全局变量的原因。在团队项目或使用重要第三方库的项目中,这是不可能管理的,并将不可避免地导致生产力损失,甚至更糟的是,可能不会立即显现的坏错误。
-
当符号只是全局的时,代码模块就不那么自我描述了。嗯,符号
map()
是从哪里来的。这是内置的吗?它是本地定义的吗?它是由某个库定义的吗?知道gutils.map()
来自哪里(来自gutils
模块)要容易得多。大量全局性的东西比把东西分解成定义良好的模块更难维护。 -
将函数定义为对其进行操作的对象上的方法有许多优点(例如ES5
.map()
和.filter()
是Array对象的方法,而不是通用全局)。现在,将非标准方法添加到现有的内置对象中被认为是不好的做法(也是出于命名冲突的原因),但鼓励添加实现标准行为的polyfill。
有关其他信息,请参阅这些参考资料:
如何以及为什么避免Javascript 中的全局变量
I';听说全局变量不好,我应该使用什么替代解决方案?
基本Javascript名称间隔模式
Javascript命名空间和模块
如何在JavaScript中声明命名空间?
至于性能主题,它不应该是您首先关心的问题,在大多数代码中也可能不是相关的问题。更重要的是,从一个健壮、可维护的编码策略开始,然后只优化性能至关重要的小块代码,而不是一开始就以性能的名义牺牲健壮性。
在性能至关重要的任何紧密循环中,您总是可以将任何函数分配给局部变量,以略微提高性能,这将比模块引用或全局引用更快(因为局部在全局之前解析)。
因此,如果你在一个模块中有gUtils.map()
,并且你想最大限度地提高特定功能的性能,你可以这样做:
function x() {
var map = gUtils.map;
for (var i = 0; i < someBigNumber; i++) {
map(...);
}
}
考虑这样的库,
_ = (function(){
lib = {};
lib.function1 = function(){
//code
};
lib.function2 = function(){
this.function1();
};
//more code
return lib;
})();
如果你使用
window.function2 = _.function2;
function2();
库在函数2中使用"this"运算符。您的方式在此处更改了函数2的范围。function2()调用将给出一个错误,表示"function1未定义"。
您不需要担心性能;即使你在符号查找中添加了一个额外的层,大多数现代JS引擎也会将其别名。你也不应该担心增加本地对象会导致异常——这是允许的。不,最大的问题是名称空间污染,你似乎对此不屑一顾。
当您的代码在本机实现这些功能的较新浏览器上运行时会发生什么?假设你在2009年写了这段代码,并在Array.prototype中添加了.map()。如果有人添加了一个新的库,该库需要一个函数签名(原生签名),而得到了一个不同的函数签名(你的),那么你的代码现在会遇到一些大问题。
如果必须这样做,至少要检查全局符号是否已经存在,例如
window.map = window.map || myLib.map;
此外,请确保任何依赖于地图实现的代码都可以向RequireJS等JavaScript依赖性管理工具发出其依赖性信号,或者您已经有了一个强大的DM系统,并且在执行任何其他代码之前附加您的本地重写(例如,不要将代码放在异步脚本标记中,不要将执行推迟到DOMContentLoaded,等等)
- 鉴于 for..在构造中,库提供的函数(如 jQuery.map() 或 _.each())有什么用
- 为什么像jQuery这样的javascript库通常更喜欢匿名函数而不是命名函数
- 如何在将Node异步函数转换为promise时使用Q库
- 重写/重写javascript库函数
- 将 jquery 库函数写入打字稿
- 是'要求(..)'常见的javascript模式或库函数
- 我应该如何命名我的javascript库函数,以便它们与普通的旧javascript区分开来
- JavaScript 库/函数,用于查找未关闭的 HTML 标记
- 调用库外部的库函数
- Rxjs 包装来自 D3 的其他库函数(可观察)
- 谷歌脚本如何动态调用库函数
- 全局命名空间中的JavaScript库函数-缺点
- 使用apply-on-Stripe Node.js库函数
- 在javascript中调用一个没有参数的C#库函数
- 如何在javascript中调试库函数的重写代码
- 如何对调用外部定义的库函数的Javascript文件进行单元测试?
- 调用jQuery库函数与变量标识
- 如何重写javascript库函数
- 覆盖es6中的库函数
- 简单但困难.如何强制外部库函数按顺序运行