how does javascript work when add number with array [duplicate] - javascript

This question already has answers here:
Why is [1,2] + [3,4] = "1,23,4" in JavaScript?
(14 answers)
Closed 5 years ago.
var array = [1,2,4];
array+1 //gives '1,2,41'.
Can anyone explain this behaviour?

Can anyone explain this behaviour?
This answer attempts to explain this behavior from the point of view of spec.
As per spec, during the run-time evaluation of +, both expressions (left and right) are converted to their primitive values.
Let lprim be ToPrimitive(lval).
Let rprim be ToPrimitive(rval).
toPrimitive tries to pass hint:number (since invoked during arithmetic evaluation) to OrdinaryToPrimitive
If hint is "string", then
a. Let methodNames be «"toString", "valueOf"».
Else,
b. Let methodNames be «"valueOf", "toString"». //this gets invoked
Since one of the values were casted to string via 4a) above, string concatenation takes place.
Hence
[1,2,4] + 1 => [1,2,4].toString() + "1" => "1,2,4" + "1" => (finally) "1,2,41"

Array is casted to string - then concatenated with integer value which is also casted to string.

When you use the + sign with a declared javascipt object (var array), even if one of the elements is a number, it doesn't perform an arithmetic addition operation - it concatenates the values as two strings.
In your example, your array [1,2,4] is being casted into a string with a value of 1,2,4. So 1,2,4 concatenated with 1 is 1,2,41

What did you expect? [2,3,5]?
You haven't wrote a mutator for array, you added 1 to array (which is an object). Why do you expect for object to be able to add 1 to it?
JS figured out you need a primitive from that object and listed that object into a string. Now it knows how to "add" 2 strings (precisely its concatenate) so it did.
If you expected an entire array to get +1 on all elements. You want:
for (var i=array .length; i--;) {
array [i]++;
}
Or
array = array.map(function(e) {return '#' + e});
Or in ES6 and beyond arrow function with map
array = array.map(i => i + 1);

When the operands of an operator are different types, they will be converted to a common type.
Both an array and a Number can be converted to string, this is called coercion.
If you would like to add 1 to an array, you can do this:
var array = [1,2,4];
array.push(1);

Related

When do for loops cause type coercion javascript? [duplicate]

This question already has answers here:
Why does javascript turn array indexes into strings when iterating?
(6 answers)
Is a JavaScript array index a string or an integer?
(5 answers)
Why is key a string in for ... in
(3 answers)
When iterating over values, why does typeof(value) return "string" when value is a number? JavaScript
(1 answer)
Closed 1 year ago.
When I do this:
const foo = [0, 1, 2]
for (i = 0; i < foo.length; i ++){
console.log(foo[i], typeof foo[i])
}
I get this:
0 number
1 number
2 number
But when I do this:
for (let item in foo){
console.log(item, typeof item)
}
I get this:
0 string
1 string
2 string
What is going on here?? What rules would I have needed to know to predict this?
Edit: I am running Node 12.18.3
There's no coercion going on here. You are actually iterating two different primitive types with your two different loops.
Traditional for loops with counters, count with numbers.
for/in loops are for iterating over properties of objects. Objects have keys/properties, which are always strings. So when you are seeing 0, 1, and 2, you are seeing the strings "0", "1", and "2".
So, when you use a for/in loop on an array instance, it's enumerated by the keys of the Array object, which include the string representation of the array indexes as well as any enumerable properties of the Array instance. You can then wind up enumerating other properties of the array besides the items in it as shown here:
const foo = [0, 1, 2];
// Add a property to the array instance
foo.bar = "baz";
for (let item in foo){
// This will log ALL the enumerable properties
// of the object, in this case, including properties
// that are not the array values.
console.log(item, foo[item]);
}
Here's another way to see this. Below is an object literal being enumerated with a for/in. Note that when the literal is created the keys don't get quotes around them, yet when their type is tested (they key name, not the key value), they are reported as strings, because they implicitly are:
let obj = {
key1: "something",
key2: "something else",
foo: 42,
false: true,
99: 100
};
for(let prop in obj){
// Note that even the unquoted key name of
// false is implicitly a string, not a Boolean
// and the 99 key is a string, not a number
console.log(prop, "(" + typeof prop + ")", obj[prop], "(" + typeof obj[prop] + ")");
}
As stated in the docs (link above):
The for...in statement iterates over all enumerable properties of an
object that are keyed by strings (ignoring ones keyed by Symbols),
including inherited enumerable properties.
You basically mixes the values of the array (first loop when you call foo[i] in the classic for) and keys / indexes of the array (when you call for ... in ....
Just try with foo = [5,6,7] and you will clearly see the difference.
for (let a in [5,6,7])
console.log(a, typeof a)
As stated in the other answer from Scott Marcus, index are like keys and are string here.
Also note that if you want loop over all elements of an array (or enumerable), use for ... of ...:
for (let a of [5,6,7])
console.log(a, typeof a)

Mapping array of numeric strings to integers returns NaN [duplicate]

This question already has answers here:
Why does parseInt yield NaN with Array#map?
(8 answers)
Closed 3 years ago.
I'm trying to convert an array of numeric strings to integers, and am seeing something odd.
const ints = ['1','2','3'].map(parseInt);
console.log(ints);
The above code returns: [1, NaN, NaN]?
The 1 gets parsed correctly, but why are the 2 and 3 getting converted to NaN?
So, I've discovered the answer.
When you pass just a function to .map, it passes ALL the arguments on to the function:
var customParseInt = function() {
console.log('arguments', arguments);
}
var arr = ['1','2','3'];
arr.map(customParseInt);
Now, the first time it's called in your .map, the first argument is '1' and the second argument is the current index of the array, which is 0.
So for the first array element, you're calling parseInt('1', 0);
And for the second array element, you're calling parseInt('2', 1); -- again, first argument is the element, second argument is the index of the array.
If you look up the documentation, the second argument for parseInt is the radix. A radix of 0 does not error (probably because it defaults to a sensible value), but a radix of 1 or 2 makes the parseInt function behave fundamentally differently.
callback is invoked with three arguments: the value of the element, the index of the element, and the Array object being traversed.
In your case you are actually calling
parseInt(1,0)
parseInt(2,1)
parseInt(3,2)
where first argument is the arrayElement and second is the radix or base
1 is valid Base 10 which is represented by radix 0
So 2 is not valid in base 1 and 3 is not valid in base 2
So the solution is to use arrow function
const ints = ['1','2','3'].map(num => parseInt(num));
console.log(ints);

Why does a number as key worked for a string key in an Object and vice-versa (Javascript) [duplicate]

This question already has answers here:
Is there any way to use a numeric type as an object key?
(11 answers)
Keys in Javascript objects can only be strings?
(8 answers)
Closed 3 years ago.
Curious about the following two cases:
First:
const key = 2;
const obj = { "2": "stackoverflow" };
obj[key]; //results in "stackoverflow" but the key is 2 and not "2"
Second:
//Vice versa case
const otherKey = "21";
const otherObj = { 21: "youtube" };
otherObj[otherKey]; //results in "youtube" but the key is "21" and not 21
My conclusion:
That since keys should be string and while finding key (when key is seemingly a number) existence in Javascript objects it does so by type-conversion comparison and not by strict or a string conversion.
Is there more to this why these cases work and am more interested in the how bit of that?
The relevant bits of the standard are
12.3.2.1 Runtime Semantics:
Evaluation
MemberExpression:MemberExpression[Expression]
...6. Let propertyKey be ? ToPropertyKey(propertyNameValue).
and
7.1.14 ToPropertyKey ( argument )
Let key be ? ToPrimitive(argument, hint String).
If Type(key) is Symbol, then Return key.
Return ! ToString(key).
In plain English, in object[whatever], whatever is converted to a string, unless it's a symbol.
Illustration:
let s = Symbol();
let o = {
'12': 1,
'foo': 2,
'true': 3,
[s]: 4
}
console.log(o[6*2])
console.log(o[{toString: () => 'foo'}])
console.log(o[1 === 1])
console.log(o[s])
The behaviour of object initializers is described in 12.2.6.7 and is exactly the same.
What happens here is something called type coercion, where a value of one type is converted to some other type for doing some operation using said value.
Since objects in Javascript store keys and values, and the keys are stored as strings, when you provide a numeric value as the key to the object, it is coerced to a string and then looked up in the object.
It'd be a little clearer if we took the example of an array. Arrays store values at indexes, which are numeric. So if we have var a = [4, 3, 5], looking up the value at index 2 using a a[2] and a["2"] would give you the same result 5, since the string "2" is coerced to a number type to support the lookup operation in the array.
Hope that helps.
From MDN Docs here
Property names must be strings. This means that non-string objects cannot be used as keys in the object. Any non-string object, including a number, is typecasted into a string via the toString method.
So, basically the keys are type coerced to strings even if they are numbers.
const object = { 21 : 'test', '21': 'message' };
console.log(object)

Why does adding an array to number return a string? [duplicate]

This question already has answers here:
Why is [1,2] + [3,4] = "1,23,4" in JavaScript?
(14 answers)
Closed 5 years ago.
var array = [1,2,4];
array+1 //gives '1,2,41'.
Can anyone explain this behaviour?
Can anyone explain this behaviour?
This answer attempts to explain this behavior from the point of view of spec.
As per spec, during the run-time evaluation of +, both expressions (left and right) are converted to their primitive values.
Let lprim be ToPrimitive(lval).
Let rprim be ToPrimitive(rval).
toPrimitive tries to pass hint:number (since invoked during arithmetic evaluation) to OrdinaryToPrimitive
If hint is "string", then
a. Let methodNames be «"toString", "valueOf"».
Else,
b. Let methodNames be «"valueOf", "toString"». //this gets invoked
Since one of the values were casted to string via 4a) above, string concatenation takes place.
Hence
[1,2,4] + 1 => [1,2,4].toString() + "1" => "1,2,4" + "1" => (finally) "1,2,41"
Array is casted to string - then concatenated with integer value which is also casted to string.
When you use the + sign with a declared javascipt object (var array), even if one of the elements is a number, it doesn't perform an arithmetic addition operation - it concatenates the values as two strings.
In your example, your array [1,2,4] is being casted into a string with a value of 1,2,4. So 1,2,4 concatenated with 1 is 1,2,41
What did you expect? [2,3,5]?
You haven't wrote a mutator for array, you added 1 to array (which is an object). Why do you expect for object to be able to add 1 to it?
JS figured out you need a primitive from that object and listed that object into a string. Now it knows how to "add" 2 strings (precisely its concatenate) so it did.
If you expected an entire array to get +1 on all elements. You want:
for (var i=array .length; i--;) {
array [i]++;
}
Or
array = array.map(function(e) {return '#' + e});
Or in ES6 and beyond arrow function with map
array = array.map(i => i + 1);
When the operands of an operator are different types, they will be converted to a common type.
Both an array and a Number can be converted to string, this is called coercion.
If you would like to add 1 to an array, you can do this:
var array = [1,2,4];
array.push(1);

Difference between "new Array(..)" and "[..]" in JavaScript? [duplicate]

This question already has answers here:
What’s the difference between "Array()" and "[]" while declaring a JavaScript array?
(19 answers)
Closed 8 years ago.
Is
var myCars=new Array("Saab","Volvo","BMW");
and
var myCars=["Saab","Volvo","BMW"];
exactly the same ?
Yes, for that case they are the same.
There is a difference if you have only one item, and it's numeric. This will create an array with a single item:
var myNumbers = [42];
but this will create an array with the length 42:
var myNumbers = new Array(42);
Yes, they are. However be aware that when you pass just a single numeric parameter to the Array constructor, you will be specifying the initial length of the array, instead of the value of the first item. Therefore:
var myCars1 = new Array(10);
... will behave differently from the following array literal:
var myCars2 = [10];
... note the following:
console.log(myCars1[0]); // returns undefined
console.log(myCars1.length); // returns 10
console.log(myCars2[0]); // returns 10
console.log(myCars2.length); // returns 1
That is one reason why it is often recommended to stick to the array literal notation: var x = [].
Yes, they are the same. There is no primitive form of an Array, as arrays in JavaScript are always objects. The first notation (new Array constructor syntax) was used heavily in the early days of JavaScript where the latter, short notation was not supported well.
Note that there is one behavioural difference: if you pass a single, numeric argument to new Array, like new Array(20), it will return a new array pre-initialised with that number of elements from 0 to n - 1, set to undefined.

Categories