cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Methods on primitives

Learn how "abc".toUpperCase() works when strings are primitives, why autoboxing uses temporary wrapper objects, and why new String(), new Number(), and new Boolean() cause surprising bugs.

By the end you’ll be able to
  • 01
    Explain wrapper objectsName the temporary object JavaScript uses for string, number, boolean, symbol, and bigint property lookups.
  • 02
    Predict autoboxingTell why methods work but custom properties on primitives do not stick.
  • 03
    Avoid wrapper trapsSpot new String, new Number, and new Boolean bugs and convert wrappers back to primitives.

The puzzle

In the Data types lesson, strings, numbers, booleans, symbols, bigints, null, and undefined were the primitive values. In the Strings lesson, you used methods such as toUpperCase(). That creates a puzzle: if "abc" is not an object, how can it have a method?

The short answer is autoboxing. When JavaScript needs a property or method on most primitives, it briefly views the primitive through a wrapper object, uses the method, then throws that wrapper away. The primitive is still just the value.

Real-life analogyA primitive is a phone; a wrapper is its case

Imagine a primitive as a phone. A method call briefly adds a case with buttons, uses one, then removes the case.

In real life: A phone
In JavaScript: The primitive string "hi"
In real life: A case fitted for a moment
In JavaScript: A temporary String wrapper object
In real life: Buttons on the case
In JavaScript: Methods from String.prototype
In real life: Taking the case off
In JavaScript: The wrapper disappears after the lookup

Where the analogy stops: The engine does not have to allocate a visible object every time. The wrapper is the specification model for property lookup; modern engines optimize the common cases.

The main definition

Autoboxing is JavaScript’s temporary conversion of a primitive into its wrapper object for property access, such as finding String.prototype.toUpperCase for "abc".toUpperCase().

Wrapper objects

COMPARE

JavaScript has wrapper constructors named String, Number, Boolean, Symbol, and BigInt. Their prototype objects hold the methods. One sentence for the next stage: methods live on objects such as String.prototype, and the prototype chain explains how lookup reaches them.

A wrapper object is not the same thing as its primitive. Compare the primitive note with the permanent sleeve below.

Primitive vs wrapper comparison
Values being comparedPop out in the code editor (opens in a new tab)JavaScript
const primitive = "x";const wrapper = new String("x");
Actual results"x" vs new String("x")
typeof primitiveprimitive: string
wrapper: object
=== primitiveprimitive: true
wrapper: false
== primitiveprimitive: true
wrapper: true
truthinessprimitive: true
wrapper: true
JSON.stringifyprimitive: "x"
wrapper: "x"
Object.keysprimitive: ["0"]
wrapper: ["0"]
valueOf()primitive: "x"
wrapper: "x"
Try it yourself

Pick a pair and compare real operations. Notice how wrappers are objects for typeof, strict equality, and truthiness, even when valueOf() gives the primitive back.

Every cell is produced from real JavaScript values in this lesson’s code.
Primitive values and wrapper objects
QuestionPrimitiveWrapper object
What is it?A plain value such as "x", 5, or falseAn object made by new String, new Number, or new Boolean
typeofstring, number, or booleanAlways object
TruthinessDepends on the primitive: false is falsyEvery wrapper object is truthy
Best useAlmost always what you wantRarely useful in app code

Autoboxing: the sleeve is temporary

STEP THROUGH

Here is the key behavior. A method call works because JavaScript can look through a temporary wrapper. A property assignment does not stick because the primitive itself has nowhere to store it. Sloppy scripts silently ignore the write; strict code throws a TypeError. Site example modules are strict, so the strict branch is the behavior you will see in normal lesson code.

Autoboxing: method call, then discarded property
Step 0 of 5Ready
Your turn: follow the blue line

Step through the method call first, then watch why a property set on a primitive does not stick. Switch modes to compare sloppy scripts with strict code.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const upper = word.toUpperCase();word.extra = 1;console.log(word.extra);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Run the property assignment as a sloppy script or strict code.

Switching modes starts a fresh test-proven replay.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

The replay labels the wrapper conceptually. It is not an engine debugger. It shows the rule that the specification describes, while real engines usually optimize the temporary wrapper away.

Where methods live

STEP THROUGH

The method is not copied onto each string. Lookup reaches shared methods, such as String.prototype.toUpperCase and Number.prototype.toFixed. Number literals need a tiny syntax trick: (5).toFixed(2) or 5..toFixed(2) works, but 5.toFixed(2) is a syntax error because the parser treats the dot as a decimal point.

Where methods live
Step 0 of 5Ready
Your turn: follow the blue line

Methods live on wrapper prototypes. Step through two safe ways to call a number method on a literal.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const fixedA = (5).toFixed(2);const fixedB = 5..toFixed(2);console.log(sameMethod);console.log(fixedA, fixedB);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Null and undefined are different

null and undefined have no wrappers. Reading a property such as null.toString or undefined.valueOf throws a TypeError instead of autoboxing.

Why new String() is a trap

SORT

The Constructors & new lesson introduced the wrapper trap. Here is the deeper rule: calling String(x), Number(x), or Boolean(x) without new converts and returns a primitive. Adding new buys a permanent sleeve: an object that behaves differently in comparisons and conditions.

Real-life analogynew String() keeps the phone case on

Autoboxing adds the case for a moment. new String() keeps it on, so every check sees an object first.

In real life: Putting on a case for one call
In JavaScript: Autoboxing for one method lookup
In real life: Keeping the case on
In JavaScript: new String("x") keeping a wrapper object
In real life: Seeing the case first
In JavaScript: typeof, ===, and if see an object

Where the analogy stops: A real sleeve can be useful clothing. Primitive wrapper objects are almost never useful in everyday JavaScript; prefer primitive values.

Good conversion vs permanent wrapperPop out in the code editor (opens in a new tab)JavaScript
const good = String(123);      // "123" primitiveconst trap = new String("x"); // object wrapperconsole.log(typeof good);console.log(typeof trap);console.log(trap === "x");
Wrapper surprises to avoid
ExpressionReal resultWhy it matters
String(123)Primitive "123"Good when you want explicit conversion.
new String("x")Object wrappertypeof is object, and strict equality with "x" is false.
new Boolean(false)Truthy objectAn if runs even though the inner value is false.
new Symbol()TypeErrorSymbols can be boxed temporarily, but cannot be constructed with new.
new BigInt(1)TypeErrorBigInts also cannot be constructed with new. Use BigInt(1).

Sort each expression by whether it leaves you with a primitive or an object.

Primitive or object?
  • String("a")
  • new String("a")
  • Object("a")
  • "a".valueOf()
  • Number("5")
  • new Number(5)
Try it yourself
0 of 6 correct

Use the rule: converters without new return primitives; new and Object(...) create wrappers.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Where you’ll use this

Most production code should use primitive values and the converter functions without new. That keeps type checks, equality, JSON, and conditions predictable.

Practical conversionsPop out in the code editor (opens in a new tab)JavaScript
function normalizeId(id) {  return String(id).trim().toLowerCase();} function isEnabled(flag) {  return Boolean(flag);}
  • String(id) is a safe way to accept a number or string ID before trimming it.
  • Boolean(flag) converts to the real primitive true or false.
  • wrapper.valueOf() recovers the primitive if a wrapper arrives from old code.

Common misconceptions

“Primitives are secretly objects.”

No. They stay primitive values. Autoboxing is a temporary lookup rule.

“If a method works, properties should stick too.”

Method lookup and property storage are different. The wrapper used for lookup is discarded.

“Loose equality means wrappers are safe.”

new String("x") == "x" is true, but ===, typeof, and truthiness still differ.

“new Boolean(false) behaves like false.”

Every object is truthy. This is why Boolean wrappers are especially dangerous in if statements.

“Symbol and BigInt work with new because they have wrappers.”

They can autobox for method lookup, but their constructors throw when used with new.

Practice: wrappers and primitives

5 EXERCISES
Exercise 1 · Warm-upPredict type and truthiness

Predict both lines, then check your answer.

Starter codePop out in the code editor (opens in a new tab)JavaScript
console.log(typeof "hi");
console.log(Boolean(new Boolean(false)));

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeExplain the disappearing property

    In a sloppy script, const s = "hi"; s.extra = 1; s.extra; does not keep extra. What value comes back?

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeCall toFixed correctly

      Write two valid calls that format the literal 5 with two decimal places.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      console.log((5).toFixed(2));
      console.log(5..toFixed(2));

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · ChallengeFix a wrapper bug

        This code enters the wrong branch. What primitive value should replace new Boolean(false)?

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        const enabled = new Boolean(false);
        if (enabled) {
          console.log("delete account");
        } else {
          console.log("stay safe");
        }

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeConvert a wrapper back

          Use valueOf() to turn a wrapper back into the primitive it contains.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          const wrapped = new String("save");
          const plain = wrapped.valueOf();
          console.log(typeof plain, plain === "save");

          Answer, then press Check. Spacing and letter case don’t matter.

            Quiz: check your understanding

            8 QUESTIONS
            Lesson quiz · 8 questionsScore: first tries count
            1. Question 1 of 8What is a wrapper object?

              Choose an answer to see the explanation.

            2. Question 2 of 8In a sloppy script, what does the string property example print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const s = "hi";
              s.extra = 1;
              console.log(s.extra);

              Choose an answer to see the explanation.

            3. Question 3 of 8What does strict code do when assigning a property to a primitive string?

              Choose an answer to see the explanation.

            4. Question 4 of 8What does the new String type and equality snippet print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log(typeof new String("x"), new String("x") === "x");

              Choose an answer to see the explanation.

            5. Question 5 of 8What does the new Boolean(false) condition print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              if (new Boolean(false)) {
                console.log("runs");
              } else {
                console.log("skips");
              }

              Choose an answer to see the explanation.

            6. Question 6 of 8Which number-literal method call is a syntax error?

              Choose an answer to see the explanation.

            7. Question 7 of 8Which call converts and returns a primitive instead of making a wrapper?

              Choose an answer to see the explanation.

            8. Question 8 of 8Which values have no wrapper methods at all?

              Choose an answer to see the explanation.

            Key takeaways

            • Primitives are not objects, but most can be temporarily boxed for property lookup.
            • Methods live on wrapper prototypes such as String.prototype and Number.prototype.
            • Properties assigned to primitives do not stick; strict code throws.
            • Avoid new String(), new Number(), and new Boolean(); use converters without new.
            • null and undefined have no wrappers.

            One-line definition: methods on primitives work because JavaScript temporarily boxes the value for lookup, then returns to the primitive.

            Up next: Type coercion.

            CompleteFrontend Clear concepts. Working examples.