In JavaScript, the rule of addition is actually simple, in only two cases:
All other types of values are automatically converted to these two types of values. In order to figure out how this implicit conversion works, we first need to understand some basic knowledge.
Note : When referring to a section in the following article (such as §9.1), it refers to the chapters in the ECMA-262 Language specification (ECMAScript 5.1).
Let's review it quickly. In JavaScript, there are two kinds of values:
In addition to the original values, all other values are values of the object type, including arrays (array) and functions.
Type conversions
The addition operator triggers three types of conversions:
Convert to original value
Convert to Digital
Convert to String
Convert a value to the original value by Toprimitive ()
The abstract operation inside the JavaScript engine ToPrimitive()
has such a signature:
ToPrimitive(input,PreferredType?)
Optional parameters PreferredType
can be Number
either String
. It only represents a conversion preference, and the conversion result must not necessarily be the type that the parameter refers to (Khan), but the conversion result must be a primitive value. If it is PreferredType
marked Number
, the following action is performed to convert input
(§9.1):
If input
it is a raw value, it is returned directly.
Otherwise, if input
it is an object. The method is called obj.valueOf()
. If the return value is an original value, the original value is returned.
Otherwise, the obj.toString()
method is called. If the return value is an original value, the original value is returned.
Otherwise, an TypeError
exception is thrown.
If it is PreferredType
marked String
, the second and third steps of the conversion operation are reversed. If you do not have PreferredType
this parameter, PreferredType
the value is automatically set according to the following rules:
Convert a value to a number by Tonumber ()
The table below explains ToNumber()
How to convert the original value to a number (§9.3)
Parameters |
Results |
Undefined |
NaN |
Null |
+0 |
Boolean |
True is converted to 1,false to +0 |
Number |
No conversion required |
String |
Parsed by a string into a number. For example, "324" is converted to 324 |
If the value entered is an object, it is first called to ToPrimitive(obj, Number)
convert the object to the original value, and then the call converts the ToNumber()
original value to a number.
Convert a value to a string by ToString ()
The following table explains ToString()
How to convert the original value to a string (§9.8).
Parameters |
Results |
Undefined |
"Undefined" |
Null |
"NULL" |
Boolean |
"True" or "false" |
Number |
Number as a string. For example, "1.765" |
String |
No conversion required |
If the value entered is an object, it is first called to ToPrimitive(obj, String)
convert the object to the original value before calling to ToString()
convert the original value to a string.
Practice a bit
The following object allows you to see the conversion process inside the engine.
Varobj = {valueof: function () {console. Log ({}; //not a Primitive},tostring: function () {console. Log ( "toString" {}; //not a Primitive}}
Number
When called as a function (rather than as a constructor call), the operation is invoked inside the engine ToNumber()
:
> Number(obj)valueOftoStringTypeError: Cannot convert object to primitive value
Addition
There is an addition operation like the following.
value1 + value2
In evaluating this expression, the internal steps are as follows (§11.6.1):
Convert two operands to the original value (the following is the pseudo-code for mathematical notation, not the JavaScript code that can be run):
javascript prim1 := ToPrimitive(value1) prim2 := ToPrimitive(value2)
PreferredType
is omitted, so Date
the value of the type is taken String
, and other types of values are used Number
.
If either PRIM1 or PRIM2 is a string, the other is converted to a string, and then the result of the two string connection operation is returned.
Otherwise, convert both PRIM1 and prim2 to numeric types, returning their and.
The expected results
When you add two arrays, the result is exactly what we expect:
> [] + []‘‘
[]
is converted to a primitive value: First try valueOf()
the method, which returns the array itself ( this
):
> var arr = [];> arr.valueOf() === arrtrue
At this point the result is not the original value, so the method is called toString()
, returning an empty string ( string
the original value). Therefore, [] + []
the result is actually a connection of two empty strings.
By adding an array and an object, the results still match our expectations:
> [] + {}‘[object Object]‘
Parse: When you convert an empty object to a string, the following results are generated.
> String({})‘[object Object]‘
So the end result is to ""
connect the "[object Object]"
two strings together.
More objects are converted to the original value example:
> 5 + new Number(7)12> 6 + { valueOf: function () { return 2 } }8> "abc" + { toString: function () { return "def" } }‘abcdef‘
Unexpected results.
If the +
first operand of the addition operation is an empty object literal, there will be a bizarre result (running results in Firefox console):
> {} + {}NaN
Oh, my God! God horse situation? The reason for this is that JavaScript interprets the first one {}
as an empty block of code and ignores it. NaN
is actually +{}
the result of an expression calculation ( +
Plus and second {}
). The plus sign you see here is +
not a two-dollar operator "addition," but a unary operator that converts the operands after it to a number, Number()
exactly as the function does. For example:
> +"3.65"3.65
The following expression is its equivalent form:
+{}Number({})Number({}.toString()) // {}.valueOf() isn’t primitiveNumber("[object Object]")NaN
Why is the first one {}
parsed into a code block? Because the entire input is parsed into a statement: If the opening brace appears at the beginning of a statement, the opening brace is parsed into the beginning of a block of code. So, you can also fix the result by forcing the input to parse into an expression: we expect it to be an expression, and the result is parsed into a statement.
> ({} + {})‘[object Object][object Object]‘
The parameters of a function or method are also parsed into an expression:
> console.log({} + {})[object Object][object Object]
You should not be surprised at the results of the calculations below, as explained above:
> {} + []0
Once explained, the above input is parsed into a block of code followed by an expression +[]
. The steps for conversion are this:
+[]Number([])Number([].toString()) // [].valueOf() isn’t primitiveNumber("")0
Interestingly, the REPL of node. js, when parsing similar inputs, is different from the parsing results of Firefox and Chrome (as with node. js using the V8 engine). The following input is parsed into an expression that is more consistent with our expectations:
> {} + {}‘[object Object][object Object]‘> {} + []‘[object Object]‘
In most cases, it's not hard to figure out how the numbers in JavaScript +
work: You can add numbers and numbers together, or strings and strings. The object value is converted to the original value before it is evaluated. If you add more than one array, you may have unexpected results.
If you want to concatenate multiple arrays, you need to use the Concat method of the array:
> [1, 2].concat([3, 4])[1, 2, 3, 4]
There are no built-in methods in JavaScript to "connect" (merge) Multiple objects. You can use a JavaScript library, such as underscore:
> var o1 = {eeny:1, meeny:2};> var o2 = {miny:3, moe: 4};> _.extend(o1, o2){eeny: 1, meeny: 2, miny: 3, moe: 4}
Note: Array.prototype.concat()
Unlike a method, the extend()
method modifies its first argument instead of returning the merged object:
> o1{eeny: 1, meeny: 2, miny: 3, moe: 4}> o2{miny: 3, moe: 4}
JavaScript {}+{}