SKU // 96

JavaScript Primitive Data

A primitive is a single, simple value with no parts you can change: a string, number, bigint, boolean, undefined, null, or symbol. Primitives are the atoms of JavaScript. This lesson covers the rules that make them behave the way they do.

// Rule 1: Primitives Are Immutable

A primitive value can never be changed. You can only replace the variable's value with a new one:

let name = "ava";

name.toUpperCase();    // returns "AVA", but name is untouched
console.log(name);    // "ava"

name[0] = "E";         // silently ignored
console.log(name);    // "ava"

name = name.toUpperCase();   // REPLACE the value: now "AVA"
ava ava
Variable vs Value
Immutable does not mean the variable is locked; that is what const is for. It means the value itself cannot be edited. let name can point to a new string any time; the old string never changes.

// Rule 2: Compared by Value

Two primitives are equal if they hold the same value, no matter where they came from:

const a = "Hel" + "lo";
const b = "Hello";
console.log(a === b);   // true

console.log(0.5 + 0.5 === 1);   // true

// Rule 3: Copied by Value

Assigning or passing a primitive always makes an independent copy:

function shout(msg) {
  msg = msg.toUpperCase() + "!";
  return msg;
}

const original = "hello";
const loud = shout(original);

console.log(original, loud);   // "hello" "HELLO!"

// But "hi".length Works?

If primitives are not objects, how can a string have a .length or a .toUpperCase() method? JavaScript briefly wraps the primitive in a temporary object, uses it, and throws it away. This is called auto-boxing:

"hi".length           // 2      (temporary String wrapper)
(3.14159).toFixed(2)  // "3.14" (temporary Number wrapper)
true.toString()        // "true" (temporary Boolean wrapper)

Because the wrapper is thrown away, anything you try to store on a primitive disappears:

let word = "cat";
word.color = "orange";       // stored on a temporary wrapper...
console.log(word.color);     // undefined  ...which is already gone
undefined
Strict Mode
Under "use strict", trying to set a property on a primitive throws a TypeError instead of silently doing nothing.
W3Schools wording
W3Schools' typeof page says a primitive value "has no properties or methods." That is only half true. The value itself has none, but auto-boxing lets you use them anyway: "hi".length works. What you cannot do is add or change properties, as the word.color example shows. In strict mode that line is TypeError: Cannot create property 'color' on string 'cat'.

// Avoid the Wrapper Constructors

new String(), new Number(), and new Boolean() create real wrapper objects, not primitives. They cause confusing bugs:

const s = new String("hi");
typeof s                 // "object"  not "string"
s === "hi"               // false

const f = new Boolean(false);
if (f) console.log("runs!")  // runs: every object is truthy, even this one
object false runs!

Calling them without new is fine and useful: it converts a value to that primitive type.

String(42)        // "42"     primitive string
Number("7")       // 7        primitive number
Boolean("")       // false    primitive boolean

// A Closer Look at Each One

Strings

Single or double quotes both work. A quote can appear inside a string as long as it is not the same kind that surrounds it:

const answer1 = "It's alright";            // single quote inside double quotes
const answer2 = 'He is called "Johnny"';   // double quotes inside single quotes

console.log(answer1);
console.log(answer2);
It's alright He is called "Johnny"

Numbers

Many languages have separate types for whole numbers (like int) and decimals (like float or double). JavaScript has one: every number is a 64-bit decimal ("floating point") number. Very large or very small numbers can be written with e, meaning "times 10 to the power of":

console.log(34.00 === 34);   // the same number: 34.00 is just 34
console.log(123e5);           // 123 times 10 to the 5th
console.log(123e-5);          // 123 times 10 to the -5th
true 12300000 0.00123

BigInt

Numbers lose accuracy above Number.MAX_SAFE_INTEGER (9007199254740991). A BigInt (added in 2020) holds whole numbers of any size. Make one with an n on the end, or from a string:

console.log(Number.MAX_SAFE_INTEGER + 2);   // too big for a number: off by one
console.log(9007199254740993n);
console.log(BigInt("123456789012345678901234567890"));
9007199254740992 9007199254740993n 123456789012345678901234567890n

Booleans

Only true or false. You usually get them from comparisons:

let x = 5;
let y = 5;
let z = 6;
console.log(x == y, x == z);
true false

undefined vs an empty string

let car;
console.log(car, typeof car);

car = "";
console.log(car === undefined, typeof car);
undefined undefined false string

An empty string is a real value with a real type. It is not "no value."

null

null means "empty on purpose." typeof null is "object", a historical bug: null is a primitive. Check for it with ===:

const carName = null;
console.log(carName === null);        // true only for null
console.log(carName == undefined);    // == treats null and undefined as equal
console.log(undefined == null, undefined === null);
true true true false

W3Schools says not to use == when checking for null. That is right when you mean only null. When you want "null or undefined," value == null is the one widely accepted use of == (see JS undefined).

// The Seven, in One Place

const s   = "text";        // string
const n   = 42;            // number
const big = 42n;           // bigint
const ok  = true;          // boolean
let   u;                   // undefined (declared, never assigned)
const nil = null;          // null      (deliberately empty)
const id  = Symbol("id");  // symbol    (unique; see Symbols)

// Quick Check

What does this log?

let word = "cat";
word.toUpperCase();
word[0] = "b";
console.log(word);
Show answer
cat. Strings are immutable: toUpperCase() returns a new string that is thrown away, and assigning to word[0] is silently ignored.

Which one creates a primitive string?

  1. new String("hi")
  2. String(42)
  3. { value: "hi" }
  4. ["hi"]
Show answer
B. String() without new converts to a primitive, "42". A makes a wrapper object, and C and D are an object and an array.

Why does console.log(9007199254740993) print 9007199254740992, and how do you store the exact value?

Show answer
It is above Number.MAX_SAFE_INTEGER, so a regular number cannot hold it exactly and rounds to the nearest value it can store. Use a BigInt: 9007199254740993n.

// Try It

  1. Click Open Playground. Call three string methods on word and confirm the original never changed
  2. Try setting a property on a number, then read it back
  3. Compare typeof "hi" with typeof new String("hi")
  4. Show that new Boolean(false) passes an if check but Boolean(false) does not
// Video Walkthroughs
Last updated: Oct 10, 2026, 1:47 AM ET