Suggest an editImprove this articleRefine the answer for “Data types in JavaScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**JavaScript data types** are seven primitives and one object type. Primitives (`string`, `number`, `boolean`, `null`, `undefined`, `symbol`, `bigint`) are copied by value. Objects (including arrays and functions) are copied by reference. ```javascript typeof 42; // "number" typeof null; // "object" (historical bug) typeof []; // "object" typeof 123n; // "bigint" ``` **Key point:** `null` is a primitive, but `typeof null === "object"`.Shown above the full answer for quick recall.Answer (EN)Image**JavaScript data types** split into two groups: seven **primitives** (immutable, copied by value) and **objects** (mutable, copied by reference). ## Theory ### TL;DR - Primitives are like printed postcards: copy one and you get an independent duplicate. - Objects are like a shared Google Doc: all "copies" point to the same underlying data. - Seven primitives: `undefined`, `null`, `boolean`, `number`, `string`, `symbol`, `bigint`. - Objects include plain objects, arrays, functions, dates, regular expressions, and more. - `typeof null` returns `"object"`, not `"null"`. A known bug from JavaScript's first version. ### Quick Example ```javascript // Primitives: assignment copies the value let a = 5; let b = a; // b gets its own copy of 5 b = 10; console.log(a); // 5, unchanged // Objects: assignment copies the reference let x = { val: 5 }; let y = x; // y points to the same object y.val = 10; console.log(x.val); // 10, x changed too ``` These two snippets explain most of the bugs developers file on this topic. ### Key Difference When you assign a primitive, JavaScript copies the actual value into a new slot in memory. The two variables become independent. Objects work differently: the variable stores a reference (a memory address), not the data itself. Assign that variable to another and both point at the same heap object. Mutate one, and the change shows up through both. ### When to Use - Loop counter → `number` primitive. - User's display name → `string` primitive. - User profile with multiple fields → object. - Toggle flag in React state → `boolean` primitive. - Form data in React state → object. - Integers beyond 2^53 - 1 → `bigint`. ### Memory Model V8 stores primitives on the stack for fast, predictable access. Objects live on the heap, and only the pointer lives on the stack. That pointer is what gets copied during assignment, which is why two variables can unknowingly share the same heap data. `Object.create` and similar APIs manipulate those heap structures directly. ### Common Mistakes **Mistake 1: treating arrays like primitives** ```javascript let arr1 = [1, 2]; let arr2 = arr1; // reference copy, not a new array arr2.push(3); console.log(arr1); // [1, 2, 3], not what you expected ``` Arrays are objects. Fix: `let arr2 = [...arr1]` or `arr1.slice()`. **Mistake 2: trying to mutate a string character by character** ```javascript let s = "hello"; s[0] = "H"; // no error, but nothing changes console.log(s); // "hello" ``` Strings are immutable. To change: `s = "H" + s.slice(1)`. **Mistake 3: comparing objects with ===** ```javascript console.log({} === {}); // false, different references console.log([1] === [1]); // false ``` Objects compare by reference, not content. For structural comparison use `JSON.stringify` or `lodash.isEqual`. For more on how `==` behaves with different types, see [type coercion in JavaScript](/questions/type-coercion-in-javascript). **Mistake 4: typeof null** ```javascript typeof null === "object" // true typeof null === "null" // false ``` This is a bug from Netscape's JavaScript 1.0. The internal type tag for `null` collided with the object type tag. Proposals to fix it were rejected over backward compatibility. Check for `null` explicitly: `value === null`. **Mistake 5: BigInt in JSON** ```javascript const id = 123n; JSON.stringify(id); // TypeError ``` JSON has no BigInt support. Convert before serializing: `id.toString()`, or pass a replacer function to `JSON.stringify`. ### Real-world Usage - **React**: props as objects `{ userId: 123, name: "Alice" }`; list keys as primitives `key={id}`. - **Express**: `req.body` is an object parsed from JSON; `res.status(200)` takes a number primitive. - **Node.js fs**: the `err` parameter in callbacks is either `null` (primitive) or an `Error` object. - **Redux**: state is an object tree; action `type` is a string primitive like `"INCREMENT"`. - **Lodash**: `_.cloneDeep(obj)` deep-copies nested objects without sharing any references. ### Follow-up Questions **Q:** What happens if you pass a primitive to a function and modify it inside? **A:** The function gets a copy. Changes inside don't affect the original. With objects the function gets the reference, so mutations are visible to the caller. **Q:** Why does `typeof null` return `"object"`? **A:** It's a bug from JavaScript's first release at Netscape. The original type tag for null matched the object type tag. Multiple proposals to fix it failed because the change would break existing websites. **Q:** Name all seven primitives. **A:** `undefined`, `null`, `boolean`, `number`, `string`, `symbol` (ES2015), `bigint` (ES2020). **Q:** How is `BigInt` different from `Number`? **A:** `Number` is a 64-bit float with a safe integer limit of 2^53 - 1. `BigInt` handles integers of arbitrary size. They don't coerce into each other implicitly, so `1n + 1` throws a TypeError. **Q (senior):** An object is passed to an async callback. The caller mutates the object before the callback runs. What does the callback see? **A:** The mutated version. The callback holds a reference to the same heap object, not a snapshot. This is a common cause of stale-data bugs in async code where a shared object is modified between scheduling and execution. ## Examples ### Primitives vs objects when passed to a function ```javascript function addTen(n) { n = n + 10; // modifies a local copy only } function addScore(obj) { obj.score = 100; // modifies the actual object } let num = 5; addTen(num); console.log(num); // 5, unchanged let user = { name: "Alice" }; addScore(user); console.log(user.score); // 100, changed ``` Pass a primitive and any mutation stays inside the function. Pass an object and the caller sees every change. I've watched this trip up junior developers who assumed JavaScript always makes a copy of what you pass in. ### Extracting a primitive from a React prop ```javascript function UserProfile({ user }) { // Extracting a string primitive from the prop object const [name, setName] = useState(user.name); // Editing the input only updates local state // user.name stays untouched return <input value={name} onChange={e => setName(e.target.value)} />; } ``` `useState(user.name)` copies the string value, not a reference to `user`. Local edits never touch the original prop. If `user` itself were passed to `useState`, any mutation to that prop object would be shared with the parent component.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.