编程是关于如何实现任何代码的决策。根据这些决定,代码将或多或少具有可读性,高效性,复杂性等。一个常见的决定也是或多或少地习惯性,即使用特定语句或您的编程语言或范例。
作为概念验证,我在Javascript中开发了两个代码片段来分析性能。目标是生成tagA|tagB|tagC
形式的字符串,其中tagX
的数量是随机的,后缀A
,B
,C
是随机整数。此外,tagX
不能重复。
第一个实现更惯用,而第二个实现更传统。接下来是每个代码片段:
习语:
performance.mark('A');
let tags = new Set(Array.from({length: tagCount}, () => Math.floor(Math.random() * 10)));
tags = Array.from(tags).map(x => `tag${x}`).join('|');
performance.mark('B');
传统
performance.mark('C');
let tagset = new Set();
let tagstr = "";
for (let tag=0; tag<tagCount; tag++) {
tagset.add(Math.floor(Math.random() * 10));
}
tagset.forEach((tag) => {
tagstr += 'tag' + tag + '|'
});
tagstr = tagstr.slice(0, -1);
performance.mark('D');
为了衡量我使用Performance Timing API
的表现结果有点令人沮丧,至少对我而言。请注意传统方式如何比另一种方式更有效。
Idiomatic: 0.436535
Traditional: 0.048177
我已经多次重复实验,结果相似
惯用法看起来非常酷而且更短,但效率低且难以阅读。
你怎么看?使用惯用编程而不是传统编程是否值得?是否有一般性答案,或者它是否完全依赖于每个案例?
代码可读性和复杂性如何?
已编辑:tagX
无法重复。
已编辑:仅供参考,我已将完整代码上传至Github:https://github.com/aecostas/benchmark-js-looping
答案 0 :(得分:5)
惯用法看起来非常酷而且更短,但效率较低且难以阅读。
如果熟悉该语言的人发现难以阅读,那么这不是“惯用语”。 (你可能会按照这个词的一个定义 - “使用许多成语” - 但这并不是人们在提到惯用代码时的意思,尽管Array.from({length}, fn)
确实是 idiom ¹用于根据JavaScript中的函数填充数组。相反,它的代码是按照语言用户所期望的方式编写的。)你可以通过命名一些内容来使它更接近:
const tagNumbers = Array.from(
{length: tagCount},
() => Math.floor(Math.random() * 10),
);
const uniqueTagNumbers = Array.from(new Set(tagNumbers));
const tagString =
uniqueTagNumbers
.map(n => 'tag' + n)
.join('|');
并利用实践中存在的效用函数的类型:
import generate from '…';
import unique from '…';
const getRandomTag = () =>
Math.random() * 10 | 0;
const tags =
generate(tagCount, getRandomTag);
const tagString =
unique(tags)
.map(n => 'tag' + n)
.join('|');
但是到目前为止,你只能使用玩具示例。
至于性能:并非一切都必须进行微观优化。这里你的两个例子具有相同的渐近时间和空间复杂度,这对于很多情况来说已经足够了。你正在用JavaScript编写,因为它的语言功能可以让你以性能为代价更好地表达自己。当它确实进行优化时,您可能希望编写更准确的基准测试(这在Node中非常难!) - 例如尝试重新排序这些测量值。
¹意思是表达语言的用户意识到的意思是没有表达的东西本身就清楚地传达了这一点。
²或者因为其他人或其他一些人认为现在你被困在他们的代码上,或者可能是出于某种原因而不是表达本身,或者前面提到的人都在同一条船上, ... 子>
³嘿嘿成语