This article was translated, original article here.
JavaScript Data Types
JavaScript is a loosely typed language, making type checking essential during variable usage. However, JavaScript doesn't strictly define primitive types. From a top-down perspective, there are only two categories: Primitive
(primitive values, or primitive data types) and object
. The distinction is simple: primitives lack properties and methods, while objects possess them. Primitives are immutable and represent the lowest-level data representation in JavaScript. Developers rarely interact directly with primitive values—when accessing them, JavaScript automatically wraps primitives in objects. For example, the string 'foo'
is a primitive. When executing 'foo'.includes('f')
, a String
object is created to wrap 'foo'
. The primitive itself has no methods/properties; it's actually accessing String.prototype.includes()
.
There are 7 primitive types:
- string
- number
- bigint
- boolean
- undefined
- symbol
- null
Except for undefined
and null
, each primitive is wrapped into a corresponding object to enable property/method access. Attempting to access properties/methods on null
or undefined
throws errors, proving primitives inherently lack these features.
Type | Object Wrapper |
---|---|
Null | N/A |
Undefined | N/A |
Boolean | Boolean |
Number | Number |
BigInt | BigInt |
String | String |
Symbol | Symbol |
Beyond primitives, JavaScript offers built-in objects like Array
and Date
to represent collections. All such objects inherit from Object.prototype
, including Function
.
Thus, JavaScript type checking fundamentally involves inspecting variable primitives and prototypes.
Type Checking Solutions
typeof
typeof
returns the type of the operand's value.
Usage
typeof operand
console.log(typeof true);
// Outputs "boolean"
Type | Result |
---|---|
Undefined | "undefined" |
Null | "object" |
Boolean | "boolean" |
Number | "number" |
BigInt | "bigint" |
String | "string" |
Symbol | "symbol" |
Function | "function" |
Any other object | "object" |
This is the most direct way to check primitives. Historically, typeof null
returns "object"
due to a bug: early JavaScript values used a type tag + value structure. Both objects (000
tag) and null (memory address 0x00
) shared the 000
tag. The typeof
implementation only checks executability (functions are executable, other 000
are objects), causing null
misidentification.
For historical context on typeof null
, see this article.
Strengths: Simple.
Weaknesses: Cannot check non-function built-in objects or custom objects; requires extra code for null.
instanceof
instanceof
checks if a constructor's prototype exists in an object's prototype chain.
Usage
object instanceof constructor
function Man(age) {
this.age = age;
}
const k = new Man(30);
console.log(k instanceof Man); // true
console.log(k instanceof Object); // true (inherits from Object)
When executing object instanceof constructor
, JavaScript checks for Symbol.hasInstance
on the constructor. If absent, it traverses the prototype chain until Object.prototype
.
Symbol.hasInstance
can be overridden, leading to inaccurate results:
class FakeArray {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance);
}
}
console.log([] instanceof FakeArray); // true (custom behavior)
Strengths: Effective for instance type checks.
Weaknesses: Fails for null
/undefined
; results can be manipulated via Symbol.hasInstance.
constructor
An instance's constructor
property references its creating constructor.
Usage
obj.constructor
All objects have a constructor
property (unless explicitly set to null
). This avoids prototype chain traversal.
Object.prototype.toString.call()
toString()
returns an object's string representation. Native Object.prototype.toString
returns '[object Type]'.
Exploiting this:
console.log(Object.prototype.toString.call([])); // "[object Array]"
Results can be altered via Symbol.toStringTag
:
class FakeArray {
get [Symbol.toStringTag]() {
return 'Array';
}
}
console.log(Object.prototype.toString.call(new FakeArray())); // "[object Array]"
Summary
Method | Strengths | Weaknesses | Use Cases |
---|---|---|---|
typeof |
Simple and intuitive; most convenient for primitive checks | Cannot check null or various objects | API data (often primitives) |
instanceof |
Traverses entire prototype chain thoroughly | Cannot check null, undefined or primitives; results can be manipulated | General object type checks |
constructor |
Constructor remains unmodified; accurate | Fails for null-constructor objects; requires constructor comparison; cumbersome for IIFE/anonymous functions | General object type checks |
toString |
Returns descriptive results; easy to use | Verbose code; results can be modified | General object type checks |
No single solution is a "silver bullet." Combining methods is often necessary. Mozilla provides a comprehensive implementation example for reference.
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.