# JavaScript Type Coercion with the `+` Operator: A Complete Guide

> Master JavaScript type coercion with the + operator. Learn how it concatenates strings or adds numbers using ToPrimitive and ToNumber abstract operations. Get the complete guide now.

- Repository: [Lydia Hallie/javascript-questions](https://github.com/lydiahallie/javascript-questions)
- Tags: deep-dive
- Published: 2026-03-04

---

**The `+` operator performs string concatenation if either operand is a string; otherwise, it converts both operands to numbers and adds them, following the ECMAScript Abstract Operations `ToPrimitive` and `ToNumber`.**

JavaScript type coercion with the `+` operator is one of the most common sources of confusion in the language. According to the `lydiahallie/javascript-questions` repository, this behavior is explicitly tested in question 15, where the interaction between numbers and strings reveals how the engine prioritizes string concatenation over arithmetic addition.

## How the `+` Operator Decides Between Addition and Concatenation

The ECMAScript specification defines the behavior of the `+` operator through the **Abstract Operation `AdditiveExpression`**. This operation is unique because it is the only binary operator in JavaScript that handles both numeric arithmetic and string concatenation.

### The ToPrimitive Conversion Process

When the JavaScript engine encounters the `+` operator, it follows these steps:

1. **Get primitive values**: The engine calls **`ToPrimitive`** on each operand with a hint of *Number*. `ToPrimitive` first attempts to invoke **`valueOf`**, and if that does not return a primitive, it falls back to **`toString`**.
2. **Check for strings**: If either resulting primitive is a string, the operation becomes **string concatenation**. Both primitives are converted to strings via `ToString` and joined.
3. **Numeric addition**: If neither primitive is a string, both are converted to numbers using **`ToNumber`** and added mathematically.

### Why Strings Win Over Numbers

The precedence rule is simple: **the string case always wins**. This means that if any operand in a `+` expression evaluates to or can be coerced into a string, the entire operation becomes concatenation.

This left-to-right associativity creates counterintuitive results. For example, `3 + 4 + '5'` evaluates to `'75'` because:
- First, `3 + 4` performs numeric addition, resulting in `7`.
- Then, `7 + '5'` encounters a string, coercing `7` to `"7"` and concatenating to `"75"`.

## JavaScript Type Coercion Examples with the `+` Operator

The `lydiahallie/javascript-questions` repository demonstrates these concepts in [`README.md`](https://github.com/lydiahallie/javascript-questions/blob/main/README.md) (lines 491-512), showing how implicit coercion affects real-world code.

```javascript
// Numeric addition (both operands coerce to numbers)
console.log(2 + 3);               // 5
console.log(2 + true);            // 3 (true → 1 via ToNumber)
console.log(2 + null);            // 2 (null → 0)

// String concatenation (string wins)
console.log('2' + 3);             // "23"
console.log(2 + '3');             // "23"
console.log(3 + 4 + '5');         // "75"

// Object coercion via valueOf/toString
console.log([] + []);             // "" (both become empty strings)
console.log([] + {});             // "[object Object]" (array → "", object → "[object Object]")
console.log({} + []);             // 0 (object → NaN, array → 0, but spec treats {} as 0 in this context)

// Explicit coercion for predictable results
const a = 2;
const b = '3';
console.log(String(a) + b);       // "23"
console.log(Number(b) + a);       // 5

```

## Edge Cases and Primitive Conversion

Understanding how different primitives and objects coerce is essential for debugging unexpected `+` operator behavior.

| Expression | Result | Reason |
|------------|--------|--------|
| `1 + true` | `2` | Boolean `true` coerces to `1` via `ToNumber`. |
| `1 + null` | `1` | `null` coerces to `0`. |
| `1 + undefined` | `NaN` | `undefined` coerces to `NaN`, poisoning the addition. |
| `{} + []` | `0` | Both become primitives: `{}` → `"[object Object]"` → `NaN`, `[]` → `""` → `0`; numeric addition results in `NaN + 0` = `NaN`, but the spec interprets `{}` as a block in statement context, yielding `0`. |
| `[] + {}` | `"[object Object]"` | `[]` → `""` (string), `{}` → `"[object Object]"`; string concatenation wins. |

## How Other Arithmetic Operators Handle Coercion

Unlike the `+` operator, **all other arithmetic operators** (`-`, `*`, `/`, `%`) consistently coerce their operands to numbers using `ToNumber`, regardless of whether strings are present.

```javascript
// Subtraction always coerces to numbers
console.log('5' - 2);     // 3 (string "5" → number 5)
console.log('5' - '2');   // 3 (both strings → numbers)

// Multiplication follows the same rule
console.log('4' * '2');   // 8
console.log('4' * 2);     // 8

// Division and modulo
console.log('10' / '2');  // 5
console.log('10' % '3');  // 1

```

This distinction makes the `+` operator uniquely prone to type coercion surprises in JavaScript codebases.

## Summary

- The `+` operator is **dual-purpose**, performing either numeric addition or string concatenation based on operand types.
- **String coercion takes precedence**: if either operand is a string (or becomes one via `ToPrimitive`), the operation concatenates.
- The engine uses **`ToPrimitive`** (trying `valueOf` then `toString`) followed by **`ToNumber`** or **`ToString`** to resolve operands.
- Unlike `+`, operators like `-`, `*`, `/`, and `%` **always coerce to numbers**, making them more predictable.
- Understanding these rules, as documented in the `lydiahallie/javascript-questions` repository ([`README.md`](https://github.com/lydiahallie/javascript-questions/blob/main/README.md) lines 491-512), helps prevent common bugs in JavaScript applications.

## Frequently Asked Questions

### What is the difference between JavaScript type coercion and type conversion?

**Type coercion** refers to the automatic, implicit conversion of values from one data type to another by the JavaScript engine, such as when using the `+` operator with mixed types. **Type conversion** (or type casting) is the explicit, manual conversion performed by developers using functions like `Number()`, `String()`, or `Boolean()`. While both achieve similar outcomes, coercion happens automatically during operations, whereas conversion requires intentional code.

### Why does `{} + []` return `0` but `[] + {}` returns `"[object Object]"`?

This discrepancy occurs due to how JavaScript interprets the leading `{}` in statement context versus expression context. In `{} + []`, the engine treats the `{}` as an empty block statement (not an object literal), leaving `+ []` which coerces the empty array to `0`. In `[] + {}`, both operands are expressions; the array becomes an empty string `""` via `toString()`, the object becomes `"[object Object]"`, and string concatenation produces the final result.

### How can I avoid unexpected type coercion with the `+` operator?

To prevent unintended coercion, **explicitly convert operands** before using the `+` operator. Use `Number()` or the unary `+` operator to force numeric addition (e.g., `Number('5') + 3`), or use `String()` to ensure concatenation (e.g., `String(5) + ' items'`). Additionally, consider using template literals for string composition, as they implicitly convert values to strings without the ambiguity of the `+` operator.

### Does the `+` operator always prefer string concatenation over numeric addition?

**Yes, when ambiguity exists.** If either operand is a string primitive, or if an object operand coerces to a string via `ToPrimitive` (specifically when `toString()` returns a primitive before `valueOf()` is tried), the `+` operator performs string concatenation. Only when both operands resolve to non-string primitives (numbers, booleans, null, undefined coerced to numbers) does the operator perform numeric addition. This "string wins" rule is hardcoded in the ECMAScript specification's `AdditiveExpression` abstract operation.