Typescript/JavaScript 中的命名空间有哪些客观的负面影响

Use*_*555 0 javascript namespaces module bundling-and-minification typescript

我在互联网上的不同文章中看过很多,也听说过很多名称空间是古老而邪恶的东西。我听说过很多人应该使用带有模块加载器而不是命名空间的模块,但我只是不明白使用它们的客观好处是什么。我读过关于命名空间的不同论点,但它们对我来说似乎并不那么令人信服。我将列出一些论点,你们请尝试用一些真实世界的例子来解释我为什么这些论点是有效的:

  • 命名空间至少创建 1 个全局变量。但这有什么问题呢?我不在乎是否有一个名为 angular 的全局变量。它会造成什么危害?
  • 使用模块,消费者决定导入变量的名称。命名导入的能力真正给了我什么?有 2 个名为 angular 的变量的可能性有多大?在那些罕见的变量名重复的情况下,我们不能这样做(我没有测试过这个,但理论上应该可以):

    var someOtherName = angular;
    
    var angular = function() {
    };
    
    Run Code Online (Sandbox Code Playgroud)
  • 带有模块加载器的模块使打包更容易,因为它们将脚本按正确的顺序排列。但是,当您通过在每个文件的顶部添加导入来明确告诉他们顺序时,他们为什么不这样做呢?类似地,当您使用 tsconfig.json 中的“outFile”选项将三重斜杠引用放在文件顶部时,Typescript 会以正确的顺序构建您的 JavaScript。这和进口有什么区别?

  • 模块加载器提高了性能。这个真的让我很困惑。假设我使用 Typescript 或 .NET 框架的捆绑工具生成一个巨大的 JavaScript 文件,性能会不会相同,因为在任何一种情况下我们都会有 1 个文件?SystemJS 根据需要动态加载这些脚本。这个更有意义,但如果我最终有一个 25kb 的 JavaScript 文件,如果它按需加载每个 kb,我真的会有多少性能提升?毕竟,它只有 25kb。

  • 即使假设模块和模块加载器比捆绑成一个文件并在 html 中引用它更好,如果我使用模块加载器来构建库,这是否意味着使用我的库的任何人也需要安装加载器依赖项?

先感谢您。

uni*_*nal 5

现在在 JavaScript 中使用命名空间被视为一个坏主意的原因有很多。所有这些原因都适用于 TypeScript,因为它只是 JavaScript 的超集。

你已经自我回答了其中的一些,但可能没有看到它们的重要性。我会尽量解决它们。

隐式依赖顺序

当您的代码通过命名空间使用某些库时,您隐式地在您的代码和您正在使用的库之间创建了依赖关系。

这意味着您必须自己管理依赖项以便正确加载它们,或者您需要指示编译器/捆绑程序以便他们可以正确安排加载顺序。

这意味着您有一个带外的地方来管理这些信息,而且很容易出错。如果明天你停止使用这个库怎么办?你会记得排除它吗?让您的工具完成它们的工作要好得多。

命名空间冲突

这是人们反对使用全局命名空间的常见原因。您可能认为这种情况很少发生,但一个例子是lodashvs underscore

命名空间版本控制

这是另一种形式的命名空间冲突。如果您的代码和您的库之一使用相同的库x但版本不同(并x在全局命名空间中公开x),那么它应该在全局命名空间中使用哪个版本x

模块解决了这个问题。

(免责声明:当前 TypeScript 类型系统无法正确处理多个版本,因此您可能会看到一些问题并需要解决它)。

禁止摇树

使用 ESM,诸如rollup和 之类的捆绑器webpack可以执行摇树。通过命名空间使用库不会向捆绑器提供任何信息来分析您的代码并删除您不需要的位。

刚性

当你通过命名空间公开你的库时,你的库的内部结构是公开的,这意味着你不能重构你的代码而不会对你的使用者造成破坏性的变化。

是的,您可以通过仔细创建适配器或别名来以某种方式避免这种情况,但这会使您的代码更难维护,并且很可能最终会变得一团糟。

安全

这是有争议的,但让您的代码在全局命名空间中可访问意味着您的代码和潜在的某些状态可以很容易地被其他代码访问和修改。

我敢肯定还有更多原因,但这些是我现在能想到的。