In JavaScript, how much is {} + {} equal?

Source: Internet
Author: User
Tags add numbers

Original article: http://www.2ality.com/2012/01/object-plus-object.html

Recently, Gary Bernhardt pointed out an interesting JavaScript quirk in a short speech video "Wat": unexpected results can be obtained when an object and an array are mixed. this article will explain in sequence how these computing results are obtained.

In JavaScript, the addition rule is actually very simple. There are only two cases: You can only add numbers and numbers, or add strings and strings, all other types of values are automatically converted to these two types of values. to understand how this implicit conversion is implemented, we need to first understand some basic knowledge. note: When a chapter is mentioned in the following article (for example, section 9. 1), refers to the ECMA-262 language specification (ECMAScript 5.1) chapter.

In JavaScript, there are two types of values: primitives and objects. The original values include:Undefined,Null, Boolean value (booleans), number (numbers), and string (strings). All other values are object-type values, including arrays and functions ).

1. type conversion

Addition operators trigger three types of conversions: convert a value to the original value, convert it to a number, and convert it to a string, which exactly corresponds to three abstract operations within the JavaScript engine: ToPrimitive (), toNumber (), ToString ()

1.1 Use ToPrimitive () to convert the value to the original value

Abstract operations inside the JavaScript EngineToPrimitive ()There is such a signature:

    ToPrimitive(input, PreferredType?)

The optional parameter PreferredType can beNumberOrString,It only represents a conversion preference. The conversion result is not necessarily the type specified by this parameter, but the conversion result must be an original value. if the PreferredType is marked as Number, the following operation is performed to convert the input value (§ 9. 1 ):

  1. If the input value is already an original value, it is returned directly.
  2. Otherwise, if the input value is an objectValueOf () method. IfValueOf () methodReturns the original value if the returned value is an original value.
  3. OtherwiseToString () method. IfToString ()If the return value of the method is an original value, the original value is returned.
  4. Otherwise, throwTypeError exception.

IfPreferredType is markedString, The order of the second and third steps of the conversion operation is changed.PreferredTypePreferredTypeThe value is automatically set according to the following rules:Objects of the Date type are set to String, and values of other types are setNumber.

1.2 convert a value to a number through ToNumber ()

The following table explainsHow does ToNumber () convert the original value to a number?(§ 9. 3 ).

Parameters Result
Undefined NaN
Null + 0
Boolean Value True is converted1,Convert false+ 0
Number Conversion not required
String Parses a string into a number. For example ,"324 "is converted324

If the input value is an objectFirstToPrimitive (obj, Number) returns this objectConvert to the original value, and then call TONumber () converts the original value to a number.

1.3 Use ToString () to convert a value to a string

The following table explainsToString() How to convert the original value to a string(§ 9. 8 ).

Parameters Result
Undefined "Undefined"
Null "Null"
Boolean Value "True" or "False"
Number Number as a string, such."1.765"
String Conversion not required

If the input value is an objectFirstToPrimitive (obj, String) returns this objectConvert to the original value, and then call ToString() Convert the original value to a string.

1.4 practice

The following object shows the internal conversion process of the engine.

Var obj = {valueOf: function () {console. log ("valueOf"); return {}; // no original value returned}, toString: function () {console. log ("toString"); return {}; // no original value returned }}

When Number is called as a function (instead of called as a constructor), the engine calls the ToNumber () operation:

> Number(obj)valueOftoStringTypeError: Cannot convert object to primitive value 
2. Addition

There is an addition operation as follows.

    value1 + value2

When calculating this expression, the internal operation steps are as follows (§ 11. 6.1 ):

  1. Convert the two operands to the original values (the following is a mathematical notation, not JavaScript code ):

        prim1 := ToPrimitive(value1)
    prim2 := ToPrimitive(value2)

    PreferredTypeThe value of Date type is omitted. Therefore, the value of Date type is String, and the value of other types is Number.

  2. IfPrim1 orIf any one of prim2 is a string, the other is also converted to a string, and the result of the two string connection operations is returned..
  3. OtherwisePrim1 andAll prim2 values are converted to the numeric type, and their sum is returned..
2.1 expected results

When the two empty arrays are added, the result is expected:

> [] + []''

[] Will be converted into an original value. First tryValueOf () method, returns the array itself(This):

> var arr = [];> arr.valueOf() === arrtrue

This result is not the original value, so you can callToString () method, returns an empty string(Is an original value). Therefore,The result of [] + [] is actually a join of two null strings..

Adding an empty array and an empty object also meets our expectation:

> [] + {}'[object Object]'

Similarly, empty objects are converted to strings.

> String({})'[object Object]'

So the final result is""And"[Object Object]" connection between two strings.

The following is an example of converting more objects into original values. do you understand this:

> 5 + new Number(7)12> 6 + { valueOf: function () { return 2 } }8> "abc" + { toString: function () { return "def" } }'abcdef'
2.1 unexpected results

If the first operand before the plus sign is an empty object literal, the result is unexpected (the following code runs on the Firefox console ):

> {} + {}NaN

What is this? The reason is that the JavaScript engine interprets the first {} as an empty code block and ignores it.NaN is actually the following expression+ {} Calculation Result(Plus sign and{}). The plus sign here does not represent the binary operator of addition, but a unary operator, which converts the operands following it into numbers, andThe Number () function is exactly the same. Example:

> +"3.65"3.65

The conversion steps are as follows:

+ {} Number ({}) Number ({}. toString () // because {}. valueOf () is not the original value Number ("[object Object]") NaN

Why is the first{} Will be parsed into code blocks.? The reason is that the entire input is parsed into a statement. If a statement starts with a left braces, the braces are parsed into a code block. therefore, you can force the input to be parsed into an expression to fix the calculation result:

> ({} + {})'[object Object][object Object]'

In addition, parameters of a function or method are parsed into an expression:

> console.log({} + {})[object Object][object Object]

After some previous explanations, you should not be surprised at the following calculation results:

> {} + []0

Once explained, the above input is parsed into a code block followed by an expression+ []The conversion steps are as follows:

+ [] Number ([]) Number ([]. toString () // because []. valueOf () is not the original value Number ("") 0

Interestingly, Node. when parsing similar input, js REPL is similar to Firefox and Chrome (and Node. js uses the V8 engine) with different parsing results. the following input will be parsed into an expression, and the result is more in line with our expectation:

> {} + {}'[object Object][object Object]'> {} + []'[object Object]'

The following is a comparison between SpiderMonkey and nodejs.

3. Miscellaneous

In most cases, you want to understand+ Number is not difficult to work: You can only add numbers or strings to strings. the object value is converted to the original value before calculation. to connect multiple arrays, use the concat method of the array:

> [1, 2].concat([3, 4])[ 1, 2, 3, 4 ]

There is no built-in method 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: andArray. prototype. concat () methods are different,The extend () method modifies its first parameter instead of returning the merged object.:

> o1{ eeny: 1,  meeny: 2,  miny: 3,  moe: 4 }> o2{ miny: 3, moe: 4 }

If you want to learn more about operators, read "Fake operator overloading in JavaScript ).

4. Reference
  1. JavaScript values: not everything is an object
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.