Javascript 为什么str.charAt(i)比Node.js中的str[i]快1.6倍 var s='',ok='h dfb ds84 78sgf ydf hjb///**',lc=0,cc=0 对于(变量i=0;i

Javascript 为什么str.charAt(i)比Node.js中的str[i]快1.6倍 var s='',ok='h dfb ds84 78sgf ydf hjb///**',lc=0,cc=0 对于(变量i=0;i,javascript,string,node.js,Javascript,String,Node.js,为什么str.charAt()始终比str[]表现出约1.6的性能改进?他们不应该以同样的方式做同样的事情吗?[]是否进行了一些额外的检查或转换,以影响速度?或者是关于我的代码 此外,为什么str.charCodeAt(i)==42比str.charAt(i)='/'快10%?从C/C++的角度来看,这毫无意义 更新:我把整个测试代码放在这里 UPDATE2:我必须说,这是使用Node.js版本0.11.4观察到的 这个测试用例显示了较小的差异。charAt()在Chrome37中慢了6%,在

为什么str.charAt()始终比str[]表现出约1.6的性能改进?他们不应该以同样的方式做同样的事情吗?[]是否进行了一些额外的检查或转换,以影响速度?或者是关于我的代码

此外,为什么
str.charCodeAt(i)==42
str.charAt(i)='/'
快10%?从C/C++的角度来看,这毫无意义

更新:我把整个测试代码放在这里

UPDATE2:我必须说,这是使用Node.js版本0.11.4观察到的

这个测试用例显示了较小的差异。charAt()在Chrome37中慢了6%,在Firefox33中快了1%。所有这些都是64

更新3,因为这似乎是Node.js问题,我添加了Node.js标记

引用Crockford的“JavaScript:the Good Parts”,第6章的开头段落,数组:

。。。阵列可以是非常快速的数据结构。不幸的是,JavaScript没有类似这种数组的东西。 相反,JavaScript提供了一个具有类似数组特征的对象。它将数组下标转换为用于生成属性的字符串。它比实际阵列慢得多

因此,在C或Java中,arr[2]是指向内存位置的直接指针,因此应该具有非常快的性能,而在JS中,arr[2]的真正含义是“将数字2转换为字符串“2”,然后将其散列以用作对象中的查找。”

哈希查找仍然非常快,但不如真正的数组快。再加上需要将数字转换为字符串,然后进行哈希运算,您就会看到性能的提升

另一方面,我相信,
str.charAt(2)
是一个本机函数,可能在幕后进行真正的数组式查找

他们不应该以同样的方式做同样的事情吗

不。除了明显不同的方式外,他们做的事情也不一样。检查和

[]是否进行了一些额外的检查或转换,以影响速度

显然。区别在于
charAt
需要将其操作数强制转换为字符串,而
[]
不需要这样做。此外,
charAt
将为越界访问返回空字符串,而
[]
将返回未定义的字符串。大多数情况下,
[]
需要检查给定的属性名称是否真的是整数,以及字符串对象上是否有具有该名称的实际属性

或者是关于我的代码

你的代码看起来不错

此外,为什么str.charCodeAt(i)==42比str.charAt(i)='/'快10%?从C/C++的角度来看,这毫无意义

请注意,JavaScript没有
char
数据类型<代码>'/'是长度为1的字符串。这似乎没有得到很好的优化(或者:很容易),整数1比较比字符串比较快


1:大多数数字,虽然“按规格”是64位浮点,但在V8中表示为31位整数。

您对此有JSPerf吗?您自己测试过还是有其他来源?另外,
s
的长度是多少?一个简短的
s
肯定会影响您的测量。我更新了代码以显示完整的测试方法,我会预期相反的结果。现在添加,此答案与主题有关,请稍后更正。那么,为什么世界上有人投票否决了它,而至少没有评论他们与它有什么问题呢?“JS:好的部分”在这个话题上似乎已经过时了。如今,每台现代发动机都在发动机罩下为
阵列
对象使用实际阵列。另外,这个问题不是关于对象或数组,而是关于字符串!我一时想不起来,但我认为底层的
str[I]
使用了相同的机制。我可以走了。无论哪种方式,a-希望看到一个好的解释,b-他们使用实际数组?我最近没有深入研究源代码。如果“charAt需要将其操作数强制转换为字符串”(额外操作)和“charAt将返回空字符串”(而不仅仅是
未定义的
,额外操作)-为什么charAt更快?实际上,强制转换为字符串可以很容易地优化(在大多数引擎中,对原语值的方法调用都会自动执行此操作)。此外,我还假设emtpy字符串的操作数少于
未定义的
——作为奖励,您可以获得类型安全性,并且可以在比较中避免类型检查。无论如何,我列出这些内容只是为了显示操作之间的差异,并不是说一个比另一个更快。我猜
[]中的属性查找
对基本值进行了类似的优化。似乎表明所有这些优化都已完成,而且这两种方法对基本字符串的优化速度类似。对字符串对象的优化速度不太高…
var s = '', ok = ' h dfb  ds84 78sgf  ydf hjb////**', lc = 0, cc = 0

for (var i = 0; i < 300000; i++) {
    s += ok[Math.floor(Math.random() * ok.length)]
}

console.time('[]')
for (var i = 0; i < s.length; i++) {
    if (s[i] == '/' && s[i+1] == '/') lc++, i++
    if (s[i] == '/' && s[i+1] == '*') cc++, i++
}
console.timeEnd('[]')
/*
console.time('charAt')
for (var i = 0; i < s.length; i++) {
    if (s.charAt(i) == '/' && s.charAt(i+1) == '/') lc++, i++
    if (s.charAt(i) == '/' && s.charAt(i+1) == '*') cc++, i++
}
console.timeEnd('charAt')
*/
console.time('regex')
var rlc = (s.match(/\/\//g) || []).length;
var rcc = (s.match(/\/\*/g) || []).length;
console.timeEnd('regex')

console.log(lc, cc, rlc==lc, rcc==cc)