最近网上流传一张图,就分析了一些解析过程

9 + "1" => “91”

ToString(9) + ToString("1"), The Addition Operator, step 7

91 - "1" => 90

91 - ToNumber("1"), The Subtraction Operator, step 6

[] + [] => “”

  • ToPrimitive([]) + ToPrimitive([]), The Addition Operator, step 5
  • OrdinaryToPrimitive([], number) + OrdinaryToPrimitive([], number), ToPrimitive, step 2.6
  • let methodNames = ["valueOf", "toString"], OrdinaryToPrimitive, step 4
  • [].valueOf() is [] not not Object, continue for loop to [].toString()
  • [].toString() + [].toString()

[] + {} => “[object Object]”

Same as previous

{} + [] => 0

  • The {} here is not parsed as an object, but instead as an empty block, see ast
  • +[]
  • ToNumber([]), Unary + Operator, step 2
  • ToNumber(ToPrimitive([]))

(!+[]+[]+![]).length => 9

  • !0 + "" + ![]
  • !0 + "" + !ToBoolean([]), Logical NOT Operator ( ! ), step 2
  • true + "" + false

++[[]][+[]]+[+[]] => “10”

  • ++[[]][ToNumber(+[])] + [ToNumber(+[])], Unary + Operator, step 2
  • ++[[]][0] + [0]
  • ++[] + [0]
  • ++ToNumber([]) + "0", Prefix Increment Operator, step 2
  • ++0 + "0"

[] == 0 => true

  • ToPrimitive([]) == 0, Abstract Equality Comparison, step 9
  • ToNumber("") == 0, Abstract Equality Comparison, step 5

var x = [0]; x == ![x] => true

  • ToPrimitive([x]) == false, Abstract Equality Comparison, step 9
  • ToNumber("0") == false

0.1 + 0.2 == 0.3 => false

6.35.toFixed(1) => 6.3

IEEE-754 double floating point
https://github.com/camsong/blog/issues/9
https://en.wikipedia.org/wiki/Double-precision_floating-point_format

9999999999999999 => 10000000000000000

2**53 == 2**53+ 1 => true

这两个我也解释不清

Math.max(), Math.min()

https://www.ecma-international.org/ecma-262/9.0/index.html#sec-math.max

The Addition Operator ( + )

  1. Let lref be the result of evaluating AdditiveExpression.
  2. Let lval be ? GetValue(lref).
  3. Let rref be the result of evaluating MultiplicativeExpression.
  4. Let rval be ? GetValue(rref).
  5. Let lprim be ? ToPrimitive(lval).
  6. Let rprim be ? ToPrimitive(rval).
  7. If Type(lprim) is String or Type(rprim) is String, then
    1. Let lstr be ? ToString(lprim).
    2. Let rstr be ? ToString(rprim).
    3. Return the string-concatenation of lstr and rstr.
  8. Let lnum be ? ToNumber(lprim).
  9. Let rnum be ? ToNumber(rprim).
  10. Return the result of applying the addition operation to lnum and rnum. See the Note below 12.8.5.

ToPrimitive ( input [ , PreferredType ] )

The abstract operation ToPrimitive takes an input argument and an optional argument PreferredType. The abstract operation ToPrimitive converts its input argument to a non-Object type. If an object is capable of converting to more than one primitive type, it may use the optional hint PreferredType to favour that type. Conversion occurs according to the following algorithm:

  1. Assert: input is an ECMAScript language value.
  2. If Type(input) is Object, then
    1. If PreferredType is not present, let hint be "default".
    2. Else if PreferredType is hint String, let hint be "string".
    3. Else PreferredType is hint Number, let hint be "number".
    4. Let exoticToPrim be ? GetMethod(input, @@toPrimitive).
    5. If exoticToPrim is not undefined, then
      1. Let result be ? Call(exoticToPrim, input, « hint »).
      2. If Type(result) is not Object, return result.
      3. Throw a TypeError exception.
    6. If hint is "default", set hint to "number".
    7. Return ? OrdinaryToPrimitive(input, hint).
  3. Return input.

OrdinaryToPrimitive ( O, hint )

When the abstract operation OrdinaryToPrimitive is called with arguments O and hint, the following steps are taken:

  1. Assert: Type(O) is Object.
  2. Assert: Type(hint) is String and its value is either "string" or "number".
  3. If hint is "string", then
    1. Let methodNames be « "toString", "valueOf" ».
  4. Else,
    1. Let methodNames be « "valueOf", "toString" ».
  • For each name in methodNames in List order, do
    1. Let method be ? Get(O, name).
    2. If IsCallable(method) is true, then
      1. Let result be ? Call(method, O).
      2. If Type(result) is not Object, return result.
  • Throw a TypeError exception.
  • The Subtraction Operator ( - )

    1. Let lref be the result of evaluating AdditiveExpression.
    2. Let lval be ? GetValue(lref).
    3. Let rref be the result of evaluating MultiplicativeExpression.
    4. Let rval be ? GetValue(rref).
    5. Let lnum be ? ToNumber(lval).
    6. Let rnum be ? ToNumber(rval).
    7. Return the result of applying the subtraction operation to lnum and rnum. See the note below 12.8.5.

    Abstract Equality Comparison

    The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:

    1. If Type(x) is the same as Type(y), then
      1. Return the result of performing Strict Equality Comparison x === y.
    2. If x is null and y is undefined, return true.
    3. If x is undefined and y is null, return true.
    4. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ! ToNumber(y).
    5. If Type(x) is String and Type(y) is Number, return the result of the comparison ! ToNumber(x) == y.
    6. If Type(x) is Boolean, return the result of the comparison ! ToNumber(x) == y.
    7. If Type(y) is Boolean, return the result of the comparison x == ! ToNumber(y).
    8. If Type(x) is either String, Number, or Symbol and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
    9. If Type(x) is Object and Type(y) is either String, Number, or Symbol, return the result of the comparison ToPrimitive(x) == y.
    10. Return false.

    Logical NOT Operator ( ! )

    1. Let expr be the result of evaluating UnaryExpression.
    2. Let oldValue be ToBoolean(? GetValue(expr)).
    3. If oldValue is true, return false.
    4. Return true.

    Unary + Operator

    1. Let expr be the result of evaluating UnaryExpression.
    2. Return ? ToNumber(? GetValue(expr)).

    https://www.ecma-international.org/ecma-262/9.0/index.html#sec-returnifabrupt-shorthands

    原文地址:https://uedsky.com/2018-07/thanks-for-inventing-javascript/
    获取最佳阅读体验并参与讨论,请访问原文