Reputation: 33900
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)
Why str.charAt() is consistently showing about 1.6 performance improvement over str[]? Aren't they supposed to do the same thing the same way? Does [] do some extra checks or conversions that affect speed? Or is it rather about my code?
Furthermore why str.charCodeAt(i) == 42
is another 10% faster than str.charAt(i) == '/'
? From C/C++ point of view it makes no sense at all.
UPDATE: I put whole test code here.
UPDATE2: I must say that this is observed using Node.js ver 0.11.4
http://jsperf.com/brackets-vs-charat3 This test case shows lesser difference. charAt() is slower 6% in chrome 37 and 1% faster in Firefox 33. All Ubuntu 64.
UPDATE 3, since this seems to be Node.js issue I add node.js tag
Upvotes: 4
Views: 1353
Reputation: 664297
Aren't they supposed to do the same thing the same way?
No. Apart from obviously different ways, they don't do the same things. Check the spec for charAt
and for []
on strings.
Does [] do some extra checks or conversions that affect speed?
Apparently. The differences are that charAt
needs to cast its operand to a string, which []
doesn't need to do. Furthermore, charAt
will return the empty string for out-of-bounds accesses, while []
will return undefined. And mostly, []
needs to check whether the given property name is really an integer, and whether there is an actual property with that name on the string object.
Or is it rather about my code?
Your code looks fine.
Furthermore why str.charCodeAt(i) == 42 is another 10% faster than str.charAt(i) == '/'? From C/C++ point of view it makes no sense at all.
Notice that JavaScript does not have a char
datatype. '/'
is a string of length 1. It seems this is not optimized well (or: easily), and an integer1 comparison is just faster than a string comparison.
1: Most numbers, though "per spec" being 64-bit floats, are represented as 31-bit integers in V8.
Upvotes: 4
Reputation: 14581
Quote from Crockford's "JavaScript: the Good Parts", opening paragraphs of Chap 6, Arrays:
... Arrays can be very fast data structures. Unfortunately, JavaScript does not have anything like this kind of array. Instead, JavaScript provides an object that has some array-like characteristics. It converts array subscripts into strings that are used to make properties. It is significantly slower than a real array...
So whereas in C or Java arr[2] is a direct pointer to a memory location and thus should have very fast performance, in JS, arr[2] really means, "convert the number 2 into the string '2', then hash it to use as a lookup in an object."
Hashed lookups are still pretty fast, but not as fast as true arrays. Add to it that the number needs to be converted to a string and then hashed, and you see the performance hit.
On the other hand, str.charAt(2)
is, I believe, a native function and is probably doing true array-like lookup under the covers.
Upvotes: -2