我是节点的新手,但我来自广泛的编程背景。在我看过的任何地方(无论是在教程中还是在我看过的生产代码中),人们都压倒性地使用硬编码字符串而不是常量来识别事件。
我从npm的最依赖包列表中选择了一个随机示例来说明我的意思:the «request» library - 为什么他们emit和consume «data»事件每次都输入字符串'data'
,而不是定义库范围的常量?
在我所知道的任何编程语言中使用常量都被认为是一种很好的做法,但是节点开发人员似乎完全满足于硬编码方法。为什么呢?
答案 0 :(得分:3)
由于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
。常量没有任何帮助,你仍然必须确保你没有错误输入它的名字。
这绝不比使用不允许输错的字符串更好或更差。
因此,长话短说,常数不会改善情况,它们只会导致更多打字并使事情变得更复杂 - 但它们并没有解决任何实际问题。
答案 1 :(得分:2)
简短的回答是字符串是JavaScript可用的最佳常量。将它们隐藏在一些静态库变量之后并不会使开发人员的代码变得更加简洁,可读(我的观点)或高效;这就是为什么它从未成为流行的惯例。
<小时/>
您的问题似乎暗示硬编码字符串在某种程度上比使用变量常量更“脆弱”。但是,我认为只有当“常量”随时间变化时才会出现这种情况,对于任何事件类型都不是这种情况,因为Node.js库(以及浏览器API)也努力维持某种程度的版本之间的向后兼容性。此外,有人错误输入变量的几率与使用硬编码字符串时相同,因为JavaScript没有编译时检查属性是否存在或其他任何东西。无论如何都无法保证。
<小时/>
您可能已经注意到JavaScript缺少枚举类型,这在很多方面都很烦人。
较早的API使用整数值来填充语言中的void
,类似于人们在Java中使用它的方式。例如,Node#nodeType
和XMLHttpRequest#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
这样的数字所提供的信息很少,而不是语义属性名{ {1}}。
JS中最好的替代方案是,现在仍然是字符串值。像fetch()
这样的现代API经常使用它们来为每个方法传递有意义的配置选项。
随着时间的推移,JS社区似乎倾向于这种方法,我认为有一些非常有说服力的理由这样做。但是,当您来自更传统的编程背景(特别是熟悉强类型语言)时,您可能需要一点时间才能对这种方法感到满意。只要保持开放的心态,尽可能多地阅读关于语言的书籍。