Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

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.
leftOperand - rightOperand
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).
10 - 3;         // 7
10.5 - 0.5;     // 10
10n - 3n;       // 7n (BigInt arithmetic)
10n - 3;        // TypeError: Cannot mix BigInt and other types

Unary Negation Operator

As a unary operator, - precedes a single operand. It coerces the operand to a numeric type and inverts its algebraic sign.
-operand
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.
-5;             // -5
-(-5);          // 5
-0;             // -0 
-0n;            // 0n (BigInt zero cannot be negative)
-10n;           // -10n

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:
// Booleans
5 - true;       // 4 (true coerces to 1)
5 - false;      // 5 (false coerces to 0)

// Null and Undefined
5 - null;       // 5 (null coerces to 0)
5 - undefined;  // NaN (undefined coerces to NaN)

// Strings
5 - "2";        // 3 (numeric strings coerce to their number equivalent)
5 - "";         // 5 (empty strings coerce to 0)
5 - "foo";      // NaN (non-numeric strings coerce to NaN)

// Unary coercion examples
-"42";          // -42
-true;          // -1
-null;          // -0

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.
const objWithSymbol = {
  [Symbol.toPrimitive](hint) {
    return 10n; // Returns a BigInt directly
  }
};
25n - objWithSymbol; // 15n

const objWithValueOf = {
  valueOf: () => "10" // Returns a string, which is then passed to ToNumber
};
25 - objWithValueOf; // 15

const date = new Date("2023-01-01T00:00:00Z");
// Dates coerce to their epoch timestamp in milliseconds via valueOf()
date - 1000;    // 1672531199000 

// Arrays (rely on toString() fallback since valueOf() returns the array itself)
5 - [2];        // 3 ([2] -> "2" -> 2)
5 - [2, 3];     // NaN ([2, 3] -> "2,3" -> NaN)
5 - [];         // 5 ([] -> "" -> 0)

IEEE 754 Edge Cases

Because JavaScript Numbers are double-precision floats, the - operator adheres to specific IEEE 754 rules regarding Infinity, -Infinity, and NaN:
Infinity - 5;            // Infinity
Infinity - Infinity;     // NaN
-Infinity - Infinity;    // -Infinity

// Any arithmetic operation involving NaN results in NaN
NaN - 5;                 // NaN
5 - NaN;                 // NaN

// Zero arithmetic
+0 - +0;                 // +0
-0 - -0;                 // +0
-0 - +0;                 // -0
Master JavaScript with Deep Grasping Methodology!Learn More