8

我是 node 新手,但我来自广泛的编程背景。在我看到的所有地方(在教程和我见过的生产代码中),人们绝大多数都使用硬编码字符串而不是常量来识别事件。

我从 npm最依赖的包列表中随机选择了一个示例来说明我的意思:«request» 库— 为什么它们每次都通过键入字符串来发出使用'data'«data» 事件,而不是定义一个库范围持续的?

在我所知道的任何编程语言中,使用常量都被认为是一种好的做法,但节点开发人员似乎完全满足于硬编码的方法。为什么?

4

2 回答 2

4

因为由于 JavaScript 的动态特性,它不适用于 Node.js。

假设,一个模块定义了一个常量data。然后它需要将其导出,作为其事件发射 API 的一部分。例如:

const data = 'data';

class Api extends EventEmitter () {
  constructor () {
    setTimeout(() => {
      this.emit(data);
    }, 2 * 1000);
  }
}

module.exports = {
  data,
  Api
};

然后,从外部来看,我们将拥有以下内容:

const foo = require('./foo');

const { Api, data } = foo;

const api = new Api();

api.on(data, () => {
  // ...
});

基本上,是这样的。现在如果你data一开始打错了怎么办?如果不是

const { Api, data } = foo;

你打错了:

const { Api, Data } = foo;

它会工作,没有任何错误。Data只是undefined。当您尝试访问不存在的对象的属性时,您不会在 JavaScript 中收到错误,您只需返回undefined.

因此,您不会收到编译器错误,但现在您正在发出(在后台)“数据”,但您正在监听的是undefined. 常量没有任何帮助,你仍然必须确保你没有打错它的名字。

这绝不比使用不允许输入错误的字符串更好或更差。

所以,长话短说,常量并不能改善情况,它们只会导致更多的输入并使事情变得更复杂——但它们并不能解决任何真正的问题。

于 2017-03-10T09:05:04.797 回答
2

简短的回答是字符串是 JavaScript 可用的最佳常量。将它们隐藏在一些静态库变量后面不会使开发人员的代码更加简洁、可读(我认为)或高性能;这就是为什么这样做从未成为流行的惯例。


脆弱性

您的问题似乎暗示硬编码字符串比使用变量常量更“脆弱”。然而,我认为只有当“常量”预计会随着时间而改变时,这才是正确的,这对于任何事件类型来说都不是这样,因为 Node.js 库(以及浏览器 API)努力保持一定程度的版本之间的向后兼容性。此外,有人错误键入变量的几率与使用硬编码字符串时相同,因为 JavaScript 没有编译时检查属性是否存在或其他任何内容。没有任何保证。


额外的上下文

您可能已经注意到 JavaScript 缺少枚举类型,这在很多方面都很烦人。

较旧的 API 使用整数值void在语言中填充它,类似于人们在 Java 中使用的方式。例如,Node#nodeTypeXMLHttpRequest#readyState都被设计成这样使用:

var node = document.createTextNode('')

console.log(node.nodeType) //=> 3
console.log(node.nodeType === Node.TEXT_NODE) //=> true

var xhr = new XMLHttpRequest()
console.log(xhr.readyState) //=> 0
console.log(xhr.readyState === XMLHttpRequest.UNSENT) //=> true

随着时间的推移,这种设计模式被认为是过时的,因为人们意识到(就像他们在 Java 中所做的那样)4与语义属性名称相比,在错误中打印数字时提供的信息是多么少UNSENT

JS 中最好的替代方法是,并且仍然是字符串值。现代 APIfetch()经常使用它们来将有意义的配置选项传递给每个方法。

随着时间的推移,JS 社区似乎倾向于这种方法,我认为这样做有一些非常令人信服的理由。但是,当您来自更传统的编程背景(尤其是熟悉强类型语言)时,您可能需要一些时间才能对这种方法感到满意。只要保持开放的心态,尽可能多地阅读有关该语言的书籍。

于 2017-03-10T09:27:55.583 回答