2.5 Operations that coerce

2.5.1 Addition operator (+)

This is how JavaScript’s addition operator is specified:

  1. function Addition(leftHandSide, rightHandSide) {
  2. let lprim = ToPrimitive(leftHandSide);
  3. let rprim = ToPrimitive(rightHandSide);
  4. if (TypeOf(lprim) === 'string' || TypeOf(rprim) === 'string') { // (A)
  5. return ToString(lprim) + ToString(rprim);
  6. }
  7. let lnum = ToNumeric(lprim);
  8. let rnum = ToNumeric(rprim);
  9. if (TypeOf(lnum) !== TypeOf(rnum)) {
  10. throw new TypeError();
  11. }
  12. let T = Type(lnum);
  13. return T.add(lnum, rnum); // (B)
  14. }

Steps of this algorithm:

  • Both operands are converted to primitive values.
  • If one of the results is a string, both are converted to strings and concatenated (line A).
  • Otherwise, both operands are converted to numeric values and added (line B). Type() returns the ECMAScript specification type of lnum. .add() is a method of numeric types.

2.5.2 Abstract Equality Comparison (==)

  1. /** Loose equality (==) */
  2. function abstractEqualityComparison(x, y) {
  3. if (TypeOf(x) === TypeOf(y)) {
  4. // Use strict equality (===)
  5. return strictEqualityComparison(x, y);
  6. }
  7. // Comparing null with undefined
  8. if (x === null && y === undefined) {
  9. return true;
  10. }
  11. if (x === undefined && y === null) {
  12. return true;
  13. }
  14. // Comparing a number and a string
  15. if (TypeOf(x) === 'number' && TypeOf(y) === 'string') {
  16. return abstractEqualityComparison(x, Number(y));
  17. }
  18. if (TypeOf(x) === 'string' && TypeOf(y) === 'number') {
  19. return abstractEqualityComparison(Number(x), y);
  20. }
  21. // Comparing a bigint and a string
  22. if (TypeOf(x) === 'bigint' && TypeOf(y) === 'string') {
  23. let n = StringToBigInt(y);
  24. if (Number.isNaN(n)) {
  25. return false;
  26. }
  27. return abstractEqualityComparison(x, n);
  28. }
  29. if (TypeOf(x) === 'string' && TypeOf(y) === 'bigint') {
  30. return abstractEqualityComparison(y, x);
  31. }
  32. // Comparing a boolean with a non-boolean
  33. if (TypeOf(x) === 'boolean') {
  34. return abstractEqualityComparison(Number(x), y);
  35. }
  36. if (TypeOf(y) === 'boolean') {
  37. return abstractEqualityComparison(x, Number(y));
  38. }
  39. // Comparing an object with a primitive
  40. // (other than undefined, null, a boolean)
  41. if (['string', 'number', 'bigint', 'symbol'].includes(TypeOf(x))
  42. && TypeOf(y) === 'object') {
  43. return abstractEqualityComparison(x, ToPrimitive(y));
  44. }
  45. if (TypeOf(x) === 'object'
  46. && ['string', 'number', 'bigint', 'symbol'].includes(TypeOf(y))) {
  47. return abstractEqualityComparison(ToPrimitive(x), y);
  48. }
  49. // Comparing a bigint with a number
  50. if ((TypeOf(x) === 'bigint' && TypeOf(y) === 'number')
  51. || (TypeOf(x) === 'number' && TypeOf(y) === 'bigint')) {
  52. if ([NaN, +Infinity, -Infinity].includes(x)
  53. || [NaN, +Infinity, -Infinity].includes(y)) {
  54. return false;
  55. }
  56. if (isSameMathematicalValue(x, y)) {
  57. return true;
  58. } else {
  59. return false;
  60. }
  61. }
  62. return false;
  63. }

The following operations are not shown here: