Suggest an editImprove this articleRefine the answer for “Boxing and unboxing in JavaScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Boxing** is the automatic wrapping of a primitive in a temporary object so you can call methods on it. Unboxing is the reverse. ```javascript "hello".toUpperCase(); // String wrapper created, method runs, wrapper discarded (42).toFixed(2); // "42.00" - same pattern for Number ``` **Key point:** wrappers are temporary. Never use `new String()` or `new Number()` - that creates a persistent object, not a primitive.Shown above the full answer for quick recall.Answer (EN)Image**Boxing** is the automatic wrapping of a primitive value in a temporary object so you can call methods on it. Unboxing is the reverse: the engine extracts the primitive back after the operation finishes. ## Theory ### TL;DR - When you call `.toUpperCase()` on a string, JavaScript wraps that string in a `String` object, runs the method, and throws the wrapper away - Unboxing happens automatically too: a wrapper object converts back to a primitive during arithmetic or comparison - The wrapper exists for one operation only. You never see it, you never hold a reference to it - Never write `new String()` or `new Number()`. That creates a persistent object, not a primitive, and breaks `===` comparisons and `typeof` checks ### Quick example ```javascript const str = "hello"; console.log(str.toUpperCase()); // "HELLO" // What the engine actually does: // 1. Sees a method call on a primitive // 2. Creates: new String("hello") <- temporary wrapper // 3. Calls: wrapper.toUpperCase() // 4. Returns: "HELLO" // 5. Discards the wrapper ``` Every `.trim()`, `.toFixed()`, `.charAt()` you call on a primitive goes through this. The primitive stays unchanged. The wrapper disappears. ### How boxing works When the engine detects a property access or method call on a primitive, it wraps the value in the matching object: `String` for strings, `Number` for numbers, `Boolean` for booleans, `Symbol` for symbols. The method runs on that wrapper. The result comes back as a primitive, and the wrapper gets discarded. Modern engines like V8 use escape analysis to recognize this pattern. In most cases they run the method without allocating a real object in memory. The cost is nearly zero. Boxing is also why `"hello".length` works. The string is not an object. But the engine creates a temporary `String` wrapper, reads `length` from it, and returns `5`. That is the whole trick. ### When to use Boxing happens automatically. You do not choose it and you cannot turn it off. What matters is knowing when it is happening: - **Method calls on primitives:** `.toUpperCase()`, `.toFixed(2)`, `.charAt(0)` - boxing is why these work at all - **Property access on primitives:** `.length` on a string triggers boxing too, not just method calls - **Debugging `typeof` surprises:** if something returns `"object"` when you expected `"string"`, someone in the codebase used `new String()` - **Avoid `new String()`, `new Number()`, `new Boolean()`** entirely in your own code ### Common mistakes **Using `new String()` thinking it behaves like a string literal** ```javascript // Wrong const a = new String("hello"); const b = new String("hello"); console.log(a === b); // false - two different objects console.log(typeof a); // "object" - not a string // Right const c = "hello"; const d = "hello"; console.log(c === d); // true console.log(typeof c); // "string" ``` `new String()` creates a persistent wrapper object. It is not a primitive. Comparisons fail. It evaluates as truthy even when the string is empty, because it is an object. The boxing the engine does during method calls is temporary. This is not. **Expecting properties to stick on a primitive** ```javascript const str = "hello"; str.customProp = "world"; console.log(str.customProp); // undefined ``` When you write `str.customProp = "world"`, boxing creates a temporary wrapper and adds the property to that wrapper. The wrapper is then discarded. The next access to `str.customProp` boxes a fresh wrapper with no properties. Primitives cannot hold properties. Only objects can. **Comparing a primitive to its wrapper object** ```javascript const x = 42; const y = new Number(42); console.log(x === y); // false - primitive vs object console.log(x == y); // true - loose equality unboxes y first console.log(typeof x); // "number" console.log(typeof y); // "object" ``` Mixing primitives and object wrappers leads to bugs that are hard to trace. Always use primitive literals. ### Real-world usage - React: `props.name.toUpperCase()` boxes the string on every render call - Express: `price.toFixed(2)` before sending a JSON response - Array callbacks: `[1, 2, 3].map(n => n.toString())` boxes each number once per call - DOM parsing: `element.getAttribute("data-id").trim()` chains two boxing operations in one line - Form validation: `input.value.length > 0` reads `.length` through boxing ### Follow-up questions **Q:** Why does `"hello".length` work if strings are primitives? **A:** Boxing. The engine wraps `"hello"` in a temporary `String` object, reads the `length` property from that wrapper, and returns `5`. The wrapper is then discarded. **Q:** What exactly is unboxing? **A:** Unboxing is when a wrapper object converts back to a primitive. It happens automatically during arithmetic: `new Number(42) + 8` unboxes the `Number` to `42` before adding. You can also call `.valueOf()` manually on any wrapper, but in practice you will not need to. **Q:** Does boxing hurt performance? **A:** Not in modern code. V8 recognizes the pattern and often skips creating a real object in memory entirely. In rare edge cases it does allocate one, but the garbage collector handles it quickly. You will not see boxing show up in any performance profile under normal conditions. **Q:** What does `typeof "hello".toUpperCase()` return? **A:** `"string"`. Even though boxing created a temporary `String` object to run the method, `toUpperCase()` returns a primitive string. The `typeof` check sees the return value, not the wrapper. **Q:** (Senior) `typeof new String("hello").toUpperCase()` also returns `"string"`, even though `new String("hello")` is an object. Why? **A:** Because `toUpperCase()` always returns a primitive string regardless of what you called it from. The `typeof` runs on the return value, not the receiver. The key difference is not the return type but the object itself: `new String("hello")` persists in memory as `"object"`, while the boxing wrapper does not. That is why `new String` is an anti-pattern, not `toUpperCase()`. ## Examples ### Method calls on a string primitive ```javascript const name = "alice"; const upper = name.toUpperCase(); // "ALICE" - boxing #1 const first = name.charAt(0); // "a" - boxing #2 const found = name.includes("alice"); // true - boxing #3 console.log(typeof name); // "string" - name never changed ``` Three boxing operations, three temporary wrappers, three discards. The variable `name` stays a primitive string the whole time. This is the pattern that runs on every string method call you have ever written. ### Validating user input in a form handler ```javascript function processInput(input) { const trimmed = input.trim(); // boxing: wraps in String, calls trim() const cleaned = trimmed.toLowerCase(); // boxing: wraps again, calls toLowerCase() const valid = cleaned.length > 0; // boxing: wraps again, reads length if (valid) { return cleaned; } return null; } console.log(processInput(" Hello World ")); // "hello world" ``` Each chained call boxes the string fresh. After reviewing several codebases I noticed developers sometimes assume these chains create objects that persist across calls. They do not. Each operation is its own temporary wrap-and-discard cycle.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.