Skip to main content
The - operator in JavaScript functions as both a binary subtraction operator and a unary negation operator, depending on its execution context (arity). In both forms, it implicitly coerces non-numeric operands to numeric primitives (Number or BigInt) via the abstract ToNumeric operation before evaluation.

Binary Subtraction Operator

As a binary operator, - computes the mathematical difference between two operands.
Evaluation Mechanics:
  1. Both leftOperand and rightOperand are evaluated.
  2. Both values are passed through the abstract ToNumeric operation.
  3. If the types of the two resulting primitives differ (e.g., one is a Number and the other is a BigInt), a TypeError is thrown.
  4. The right numeric value is subtracted from the left numeric value according to IEEE 754 double-precision floating-point arithmetic (or BigInt arithmetic).

Unary Negation Operator

As a unary operator, - precedes a single operand. It coerces the operand to a numeric type and inverts its algebraic sign.
Evaluation Mechanics:
  1. The operand is evaluated.
  2. The value is passed through the abstract ToNumeric operation.
  3. If the resulting value is NaN, the result remains NaN.
  4. Otherwise, the sign of the numeric value is inverted.
  5. Edge Case for Zero: For Number types, negating 0 yields -0 (JavaScript distinguishes between +0 and -0). However, BigInt does not possess a negative zero concept; negating 0n evaluates strictly to 0n.

Implicit Type Coercion (ToNumeric)

Because the - operator is strictly mathematical, it forces type coercion on non-numeric types. When applying the - operator to non-numeric primitives, the JavaScript engine applies ToNumeric, which delegates to ToNumber for standard primitives:

Object Coercion

When an operand is an Object, JavaScript attempts to convert it to a primitive value using the abstract ToPrimitive operation, prioritizing the number hint. The resolution follows strict rules:
  1. If the object defines a [Symbol.toPrimitive] method, it is called exclusively with the "number" hint. If this method returns an object instead of a primitive, a TypeError is thrown immediately (it does not fall back to other methods).
  2. If [Symbol.toPrimitive] is absent, the engine falls back to calling valueOf(). If valueOf() returns a primitive, that value is used.
  3. If valueOf() is absent or returns an object, the engine falls back to calling toString().
Once a primitive is successfully returned, it is processed by ToNumeric. If the returned primitive is a BigInt, ToNumeric returns it directly. If the primitive is any other type, it is subjected to ToNumber coercion rules.

IEEE 754 Edge Cases

Because JavaScript Numbers are double-precision floats, the - operator adheres to specific IEEE 754 rules regarding Infinity, -Infinity, and NaN:
Tired of Poor JavaScript Skills? Fix That With Deep Grasping!Learn More