JavaScript将数组连接成字符串

14

我正在使用D3.js,经常需要动态构建transform属性(或在path元素上的d属性)。这两种情况通常需要多个逗号分隔的数字。

有时我会通过将数组连接为字符串来构建我的字符串:

var x = 0,
y = 1,
path = 'M0,0 L' + [x, y];

有时我通过手动添加逗号来构建我的字符串:

var x = 0,
y = 1,
path = 'M0,0 L' + x + ',' + y;

我已经决定尝试坚持使用一种方法,现在正在考虑哪种方法更好。

以下是我考虑过的几个因素:

  • 我知道调用join()比手动连接逗号慢,但当浏览器将数组连接到字符串时,它会这样做吗?
  • 第二种格式在任何浏览器中都可以使用。是否有任何不支持第一种格式的浏览器?
  • 第一种格式使用较少字符(保持文件大小低始终是一个优点)。
  • 就个人而言,我认为第一种格式更易读。

这两种方法中有一种明显比另一种更好吗?还是说我太过于挑剔了?


1
你只是在挑剔而已 :-) 我会选择更易读的那一个(在我看来,那是第二个)。 - bfavaretto
2个回答

20
当JavaScript将数组强制转换为字符串时,实际上会在数组上调用.join(',') 方法。因此,手动使用.join(',') 比使解释器注意到您正在强制转换数组更快。因此:x + ',' + y 是最快的,[x,y] .join(',')是最佳实践(因为它使修改行为更容易),而 [x,y] 比手动调用.join 略慢,有时可能难以阅读,但更方便。

我很惊讶地发现x + ',' + y实际上比 [x,y] 快多了。在我的情况下,它大约快了4倍。(http://www.jsfiddle.net/8VqEP) - Towler

5

简短的回答:使用array.join方法。

详细的解释:

首先,字符串拼接不如使用array.join()方法快,而是更慢。这是因为每次拼接都会销毁两个字符串并创建一个新的字符串。

考虑下面的代码:

<script>
function concat(){
var txt = '';
for (var i = 0; i < 1000000; i++){
txt =+ i + ',';
}
}

function arr(ar){
var txt = 'asdf' + ar;
}

ar = [];
for (var i = 0; i < 1000000; i++) {
ar.push(i);
}

concat();

arr(ar);

alert('done!');
</script>

将它粘贴到一个html文件中。然后对其进行剖析。在我的机器上(core i7EE,16GB RAM,SSD磁盘,IE9),arr()花费0毫秒,而concat()花费12毫秒。请记住,这是超过一百万次迭代的(在IE6上,相同的测试会非常不同,concat()需要几秒钟)。

其次,当只有两个值时,连接将与array.join相同。所以对于您的示例,从性能的角度来看,它们都是等效的。如果您将上述代码将1000000更改为4,则concat和arr均需要执行0ms。这意味着您特定流程的差异要么不存在,要么非常微不足道,无法在配置文件中显示。

第三,现代浏览器使用array.join()优化字符串连接,因此从性能角度来看,讨论可能是无用的。

那就留下样式。就我个人而言,我不会使用第一种形式,因为我不喜欢手动连接字符串(当你有2个变量时,这是相当简单的,但如果你有10个变量呢?那将成为一行非常长的代码。如果您收到一个包含n个值的数组,那该怎么办?for循环进入)。我也不会使用第二种形式,因为正如另一个答案中指出的那样,该值被强制转换为字符串,这意味着一些隐式的转换正在进行。问题在于隐含的部分。我现在知道数组在被强制转换时使用逗号连接,但如果规范发生变化或某个天才决定更改代码库中Array.prototype的toString实现会发生什么?只是为了好玩在jsfiddle中运行此命令:

Array.prototype.toString = function() {
return 'not the expected result!';
}

alert([1, 2]);

你能猜出答案吗?(上面的代码将执行与您的代码相同类型的数组转换。通过toString()方法进行强制转换)

如果您使用array.join(','),您将通过声明以下内容使您的代码具备未来性:1)无论toString实现如何,都将连接您的数组;2)它将用逗号连接。


我同意你关于隐式转换的观点 - 这是我没有想到的。然而,我不同意你的性能测试。我是在一行代码中构建我的字符串,而不是在循环中迭代地构建。一个更好的测试案例应该像这样(请参见此fiddle http://jsfiddle.net/8VqEP/)。你会看到这里TenorB的答案中的性能评级是准确的。 - Towler
测试的目的是展示任何差异都是微不足道的(12毫秒几乎没有什么区别),并且说明在处理大字符串时,字符串连接速度较慢(1000000次迭代会生成一个很长的字符串)。您的fiddle比较了连接数组和连接一个非常小的字符串。稍作修改后(您在每次迭代中构建了数组,这可能会污染测试结果,因为我们正在对连接进行性能分析,而不是对象创建),我回到了我的第二个观点。我的时间分别是502、2和91,即最慢测试每次迭代大约需要0.000502毫秒。微不足道。 - Nicolas Straub
这让我们回到了我发帖的初衷。由于性能可以忽略不计,你应该使用array.join,原因如上所述。 - Nicolas Straub
似乎jsfiddle会增加一些性能分析的开销。如果你在本地运行代码(即从加载到浏览器中的html文件中运行),结果是266、238、180;使array.join()成为最快的(这只是我的结果,它们可能在你的环境中不同,但它们证明了我的观点:性能是可以忽略不计的)。 - Nicolas Straub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接