JavaScript values include seven primitive types and objects, with dynamic bindings, explicit and implicit conversion, reference identity, nullish states, Symbols, and BigInts requiring distinct boundary rules.
Use precise checks for each question, preserve valid falsy values, validate unknown external input, and choose serialization and numeric representations before data crosses a protocol.
JavaScript is dynamically typed, which means the type belongs to the value, not permanently to the variable. When you write let total = 100, the value 100 is a number. If later you write total = "100", the same variable now holds a string. JavaScript allows this, so the developer must keep track of what kind of value is expected at each point in the program.
Dynamic typing is useful when building flexible browser logic, reading JSON from APIs, or handling optional user input. It can also create bugs when a value looks correct but has the wrong type. For example, "10" + 5 produces "105" because one value is a string, while 10 + 5 produces 15 because both values are numbers.
let result = 10;
console.log(typeof result); // "number"
result = "10";
console.log(typeof result); // "string"
console.log(10 + 5); // 15
console.log("10" + 5); // "105"
Primitive values are simple values that are not objects. They are stored and compared by value. JavaScript has seven primitive data types: string, number, bigint, boolean, undefined, null, and symbol. Most beginner programs use string, number, boolean, undefined, and null first, then later learn symbol and bigint for special cases.
A string stores text, a number stores integer or decimal numeric values, a boolean stores true or false, undefined means a value has not been assigned, and null is an intentional empty value. BigInt is used for integers larger than Number.MAX_SAFE_INTEGER. Symbol creates unique identifiers, often used as object keys in advanced code.
| Type | Meaning | Example | Important note |
|---|---|---|---|
| string | Text data | "JavaScript" | Use quotes; template literals use backticks. |
| number | Integer or decimal number | 42, 19.5, NaN | All normal numbers use the same number type. |
| bigint | Very large integer | 9007199254740993n | Cannot be mixed directly with number values. |
| boolean | Logical true or false | true, false | Common in conditions and flags. |
| undefined | No value has been assigned | let name; | Often appears when a property or return value is missing. |
| null | Intentional empty value | selectedUser = null | typeof null returns "object" because of an old JavaScript behavior. |
| symbol | Unique identifier | Symbol("id") | Useful for unique object keys and advanced APIs. |
Objects, arrays, and functions are reference values. They can contain multiple pieces of data or behavior. An object groups named properties, an array stores ordered items, and a function stores reusable behavior that can be called. In JavaScript, arrays and functions are also objects, which is why typeof [] returns "object" and typeof function(){} returns "function".
Reference values are compared by identity, not by visible contents. Prefer checking the specific property, id, length, or serialized shape you actually care about; avoid expecting === to compare two separate object or array literals by contents.
const first = [1, 2, 3];
const second = [1, 2, 3];
const same = first;
console.log(first === second); // false
console.log(first === same); // true
console.log(Array.isArray(first)); // true
The typeof operator is the fastest way to inspect most primitive values. It returns strings such as "string", "number", "boolean", "undefined", "bigint", "symbol", "object", and "function". It is useful, but not perfect: typeof null returns "object", and arrays also return "object".
For arrays, use Array.isArray(). For null, use value === null. For class instances or built-in object types, instanceof can check whether an object appears in a constructor prototype chain. In everyday beginner code, typeof, Array.isArray, and strict equality solve most type checks clearly.
console.log(typeof "hello"); // "string"
console.log(typeof 42); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object"
console.log(Array.isArray([])); // true
console.log(null === null); // true
console.log(new Date() instanceof Date); // true
The ECMAScript 2026 ReservedWord grammar lists 38 tokens. That total includes true, false, and null; the future-reserved word enum; and await and yield, whose restrictions depend on context. A different total may be quoted when a source counts only always-reserved language keywords or also includes contextual keywords.
Words such as async, as, from, get, of, and set have grammatical meaning in specific positions but are not always reserved identifiers. Strict mode also restricts let, static, implements, interface, package, private, protected, and public. When a name could be confused with language syntax, use a clearer identifier such as className, packageName, isPublic, or orderStatus.
| Category | Common keywords | Used for | Naming advice |
|---|---|---|---|
| Declarations | class, const, function, var | Declaring classes, constants, functions, and variables | These four are part of the 38-token ReservedWord list. |
| Control flow | break, case, catch, continue, debugger, default, do, else, finally, for, if, return, switch, throw, try, while, with | Branching, looping, exception flow, and function return | All 17 are reserved words. |
| Modules and objects | export, extends, import, in, instanceof, new, super, this | Modules, classes, object creation, and property checks | All eight are reserved words. |
| Operators | delete, typeof, void | Property deletion, type inspection, and undefined-result expressions | All three are reserved words. |
| Literals and special cases | false, null, true, enum, await, yield | Literal tokens, a future-reserved word, and context-sensitive restrictions | These six complete the 38-token ReservedWord list. |
| Strict-mode restrictions | let, static, implements, interface, package, private, protected, public | Identifiers restricted by strict-mode and class grammar rules | Keep these separate from the 38-token ReservedWord grammar. |
| Contextual keywords | as, async, from, get, meta, of, set, target | Grammar-specific meanings while remaining valid identifiers elsewhere | Their presence is why a single "keyword count" needs a counting rule. |
| Naming rule | Choose descriptive identifiers such as className, requestStatus, or shouldContinue | Keeping names distinct from syntax and framework conventions | Do not depend on a word being accepted in only one execution context. |
The most common confusion is treating null and undefined as the same thing. undefined usually means JavaScript did not receive or assign a value. null usually means the developer intentionally placed an empty value. Another common mistake is assuming arrays have a separate typeof result. They do not; use Array.isArray instead.
Another important habit is converting user input before doing numeric work. Form values are strings. URL parameters are strings. localStorage values are strings. If you plan to add, compare, sort, or calculate with those values, convert them with Number(), parseInt(), parseFloat(), or a stricter validation step first.
const quantityInput = "3";
const priceInput = "250";
const quantity = Number(quantityInput);
const price = Number(priceInput);
if (Number.isFinite(quantity) && Number.isFinite(price)) {
console.log(quantity * price); // 750
}
Symbols and BigInts require explicit boundary design. Symbols are unique property keys that JSON omits, while BigInt cannot be mixed with Number arithmetic or serialized by JSON without a chosen representation. Convert at protocol boundaries with range, precision, and compatibility checks.
Use `typeof`, `Array.isArray`, null checks, and schema validation for different questions. No single operator proves that external data is a valid domain value. Narrow unknown input once, then keep internal contracts specific.
Explicit conversion functions communicate intent but still need validation. `Number` accepts formats and values that may be invalid for a business field, `String` produces technical representations, and `Boolean` follows truthiness rather than domain rules. Parse, range-check, and normalize at the boundary that understands the data.
Object assignment copies references. Spread and Object.assign make shallow copies of enumerable own properties, while nested objects remain shared and accessors may be evaluated. Use structuredClone only for supported structured data and understand transfer behavior; class prototypes, functions, and external resources require domain-specific copying.
Equality does not provide deep structural comparison. Define which fields establish identity, which order matters, and how numeric edge cases are handled. Stable IDs often make collection updates clearer than repeated whole-object comparison.
function describeValue(value) {
if (value === null) return "intentional empty value";
if (Array.isArray(value)) return "array with " + value.length + " items";
return typeof value;
}
console.log(describeValue("TL")); // string
console.log(describeValue([1, 2, 3])); // array with 3 items
console.log(describeValue(null)); // intentional empty value
// Bad: class is a reserved keyword
// const class = "Beginner";
// Good: use a descriptive identifier
const className = "Beginner";
const userStatus = "active";
console.log(className, userStatus);
Modern JavaScript has seven primitive data types: string, number, bigint, boolean, undefined, null, and symbol. Objects, arrays, and functions are reference values.
It is an old JavaScript behavior kept for compatibility. For null, use value === null instead of relying on typeof.
ECMAScript 2026 lists 38 ReservedWord tokens. Counts vary when a list excludes literal words such as true and null, treats await and yield by context, or adds contextual and strict-mode-only restrictions.
Explore 500+ free tutorials across 20+ languages and frameworks.