Skip to main content
All posts

Is Everything in JavaScript Really an Object?

Bosh4 min read

When I was learning JavaScript, I'd occasionally come across this claim in tutorials or discussion forums:

“In JavaScript, everything is an object.”

Without really thinking about it, I picked up the idea that all variables in JS were objects. Now that I use JavaScript extensively at work and understand it a little better, I wanted to come back to that claim.

Let's get the answer out of the way: it isn't correct.

But if you're reading this, you're probably like me: you want to know why people say “everything in JavaScript is an object,” what supports that argument, and what the counterarguments are. Let's look at both sides and clear up a few JavaScript concepts along the way.

Where Does “Everything Is an Object” Come From?​

JavaScript's Primitive Types​

Before we look at the claim, we need to understand JavaScript's basic data types. JavaScript has seven data types: Undefined, Null, Boolean, Number, String, Symbol (added in ES6), and Object. The first six are primitive types, while Object is a complex type.

So not every data type in JavaScript is inherently an object. Primitives are distinct from objects and don't have object properties or methods of their own. Under some circumstances, though, they can behave like objects. That's one reason the “everything is an object” idea came about.

The Origin of the Claim​

Although primitives and objects are clearly different, in practice we often find that we can work with primitives as if they were objects. For example:

const a = "123";
console.log(a.__proto__)
/* String {
anchor: ƒ anchor()
at: ƒ at()
big: ƒ big()
blink: ƒ blink()
bold: ƒ bold()
charAt: ƒ charAt()
charCodeAt: ƒ charCodeAt()
codePointAt: ƒ codePointAt()
concat: ƒ concat()
constructor: ƒ String()
...
} */

const b = "456";
console.log(b.substr(1)); // "56"

Here, a and b hold primitive String values, but we can access __proto__ and call various methods on them. That seems to support the idea that “primitives are objects too.”


What's Wrong with That Reasoning?​

Wrapper Objects​

That interpretation isn't correct, though. What we're seeing is JavaScript's wrapper object, or primitive wrapper, mechanism. When we call a method on a primitive value, JavaScript temporarily creates a corresponding wrapper object, allowing the value to behave like an object. For example:

const str = "hello";
console.log(str.toUpperCase()); // "HELLO"

Here, str is a string. When we call toUpperCase, JavaScript temporarily creates a String wrapper object. Internally, the process looks like this:

  1. Create a String instance.
  2. Call the specified method on that instance.
  3. Discard the instance.

We can illustrate it like this:

const tempStr = new String("hello");
const result = tempStr.toUpperCase();
tempStr = null;
console.log(result); // "HELLO"

Checking the Wrapper Behavior​

This mechanism makes primitives look like objects in some situations, but they aren't actually objects. The wrapping is temporary. The following example helps demonstrate that:

var str1 = "hello";
var str2 = new String("hello");

console.log(str1.__proto__ === str2.__proto__); // true
console.log(str1 instanceof String); // false
console.log(str2 instanceof String); // true

When str1 accesses __proto__, JavaScript temporarily instantiates an object with new String(), so at that moment the two values have the same constructor and prototype. That doesn't mean str1 is actually an object.

Temporary wrapping can easily lead developers to think primitives are objects. We need to keep the fundamental difference between primitive values and objects in mind: “everything is an object” isn't an accurate description of JavaScript.


Wrapping Up​

Common Misconceptions​

Misconception 1: All data types are objects
JavaScript's primitive types aren't objects. These types include Undefined, Null, Boolean, Number, String, and Symbol. They are fundamentally different from objects. Being temporarily wrapped in an object in certain situations doesn't make them objects themselves.

Misconception 2: Primitives have object methods and properties
This comes from JavaScript's temporary wrapping behavior at runtime. When we call a method on a primitive, JavaScript creates a wrapper object that provides object-like behavior. It's a temporary process; the methods and properties don't belong to the primitive itself.

Misconception 3: Every variable can use the proto property
The proto property accesses an object's prototype. When a primitive is temporarily wrapped, we can access proto through that wrapper. The primitive itself doesn't have the property; it belongs to the temporary wrapper object.


Reference​