KevBot
KevBot

Reputation: 18908

Why is an array with only 1 numerical item usable with some arithmetic?

I don't understand why an empty array, or an array with only 1 "numerical" value can be used in certain calculations.

[] * [] === 0 //true

[2] * [2] === 4 //true

["2"] * ["2"] === 4 //true

However, it does not seem that is always the case with every operator.

[2] + [1] === 3 // false, actual result is "21"

[2] - [1] === 1 // true

I also checked these, and saw expected results:

[4] === "4" // false
[4] === 4 // false

In most cases, I would expect NaN in any of these mathematical operations. What is it about JavaScript arrays that allows this? Is it because the array toString method is being used somehow internally?

Upvotes: 1

Views: 66

Answers (4)

isvforall
isvforall

Reputation: 8926

When you do mathematical operations on the arrays JavaScript converts them to the strings. But string doesn't have multiply operator and then JavaScript converts them to the numbers because you try to multiply them:

[] * [] === 0 //  [] -> '' -> 0, result is 0 * 0 

[2] * [2] === 4 // [2] -> '2' -> 2, result is 4 * 4

["2"] * ["2"] === 4 // ["2"] -> '2' -> 2, result is 4 * 4

String has a + operator:

[2] + [1] === 3 // '2' + '1', result is "21"

but doesn't have a - operator, therefore JavaScript converts them to the numbers too:

[2] - [1] === 1 // true, because they are numbers

=== it's strict equality, means that the objects being compared must have the same type.

[4] === "4" // false, you are comparing array with a string
[4] === 4 // false, you are comparing array with a number

Upvotes: 1

zetavolt
zetavolt

Reputation: 3217

In regards to +, + is a coercive operator on Strings, irrespective of it being the lvalue and rvalue, I'll quote the specification here:

If Type(lprim) is String or Type(rprim) is String, then Return the String that is the result of concatenating ToString(lprim) followed by ToString(rprim)

Multiplication however doesn't follow the same rules, it does however apply ToNumber, which as you've noticed, casts a [Number] to -> Number (+ does this as well, but it is a later step in the operator's definition)

Your last statement is answered by two rules of the SameValue algorithm defined in the spec, namely, if two values are of a different type, return false, alternatively, if two objects refer to the ptr, return true. Thus

a = [1];
b = [1];
a === b; // false

Upvotes: 1

Henrique Barcelos
Henrique Barcelos

Reputation: 7900

The same ol'problem of having + as string concatenation operator.

An array in Javascript is an Object. When you try to coerce objects into primitive values, there is an order to follow:

  1. <obj>.toString()
  2. <obj>.toNumber()
  3. <obj>.toBoolean()

If you're using the * operator, coerce into string is not possible, so the interpreter goes to toNumber().

When you're using the + operator, the first attempt will be toString(). Since + is also the string concat operator, then the expression will be evaluated as an array.

Yeah, can get ugly.

Edit:

Some further details can be found here.

Upvotes: 1

arcyqwerty
arcyqwerty

Reputation: 10695

The arrays are coerced into strings, such that [] == "", [1] == "1", and [1, 2] == "1,2".

When you do certain mathematical operations on strings, they are coerced into Number types.

For example, when you do [2] * [2] it becomes "2" * "2" which becomes 2 * 2. You can even mix types and do [2] * 2 or "2" * [2].

When you try to use +, it attempts to concatenate the strings instead of coercing the strings to numbers. That's why "2" + "2", "2" + [2], and [2] + [2] each give you "22".

Upvotes: 5

Related Questions