The following is from an interactive session in the Chrome console:
myarray
//-> [67, 65, 84]
String.fromCharCode(67)
//-> "C"
String.fromCharCode(67).length
//-> 1
String.fromCharCode(myarray[0])
//-> "C"
String.fromCharCode(myarray[0]).length
//-> 1
myarray.map(String.fromCharCode)
//-> ["C", "A", "T"]
myarray.map(String.fromCharCode)[0]
//-> "C"
myarray.map(String.fromCharCode)[0].length
//-> 3
Can anyone explain why the last operation returns 3
?
In JavaScript, fromCharCode() is a string method that is used to create a string from a sequence of Unicode values. Because the fromCharCode() method is a static method of the String constructor, it must be invoked through the String constructor object rather than through the particular instance of the String class.
map does not mutate the array on which it is called (although callbackFn , if invoked, may do so). The range of elements processed by map is set before the first invocation of callbackFn .
Definition and Usage. map() creates a new array from calling a function for every array element. map() calls a function once for each element in an array. map() does not execute the function for empty elements. map() does not change the original array.
The map() method in JavaScript creates an array by calling a specific function on each element present in the parent array. It is a non-mutating method. Generally map() method is used to iterate over an array and calling function on every element of array.
Very interesting question.
And the answer is: The reason you're getting 3
at the end is that fromCharCode
returns a string with as many characters as there are arguments in the call to it, and map
calls the callback function with three arguments: The value of the element, the index of the element, and the object being traversed. Thus, a string with three characters, but not three readily-displayed characters. Tricky.
Specifically, we get "C"
for the first argument; character 0 for the second argument (since we're looking at [0]
; it would be 1 for [1]
, etc.), and a character based on coercing the array into a number (using whatever rules fromCharCode
uses for that; Šime Vidas says below that it'll do ToUInt16
on it, which will result in 0
).
So, for instance:
> String.fromCharCode(67, 0, [67, 65, 84]).length
3
...just as with the call from map
.
For clarity:
> String.fromCharCode(67, 0, [67, 65, 84]).length
3
> String.fromCharCode(67, 0, null).length
3
> String.fromCharCode(67, 0, 0, 0, 0, 0, 0).length
7
If we ensure we only pass it the one argument at a time, we don't see that unexpected effect, so while using it directly gives us a result I think most of us wouldn't expect:
> [67, 65, 84].map(String.fromCharCode)
["C", "A", "T"]
> [67, 65, 84].map(String.fromCharCode)[0]
"C"
> [67, 65, 84].map(String.fromCharCode)[0].length
3
...this gives us a more easily-understood result:
> [67, 65, 84].map(function(value) { return String.fromCharCode(value); })
["C", "A", "T"]
> [67, 65, 84].map(function(value) { return String.fromCharCode(value); })[0]
"C"
> [67, 65, 84].map(function(value) { return String.fromCharCode(value); })[0].length
1
I can't expand much on T.J. Crowder's great answer, but I can provide a workaround for this specific problem.
Rather than
myarray.map(String.fromCharCode);
Use
String.fromCharCode.apply(String, myarray).split("");
Aside from the benefit of returning the expected result, this also works without relying on the ECMAScript 5th Edition method, Array.prototype.map
, thus making it more compatible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With