Maximo Martinez Soria
Published on

Not everything is an object in JavaScript

"Everything in JavaScript is an object" is a well known sentence that almost everyone have heard at least once. However, this is not correct at all.

In order to understand the differences between JavaScript datatypes, let's split them into two categories: Primitive datatypes and Objects.

Primitive datatypes

Primitive datatypes are those things that aren't objects. They are just what they are.

For example: a string is a string and that's it.

There are seven primitive datatypes in the language so far:

  • String: usually texts, but it can be everything you insert into double or single quotes.
  • Number: quite self-descriptive. It can only save 64 bits.
  • BigInt: same as Number, but it can save more than 64 bits.
  • Boolean: only two possible values: true or false.
  • Symbol: it's an anonymous and unique value.
  • undefined: it's used by JavaScript to say that something doesn't have a value.
  • null: it's an invalid or nonexistent value. You can use it to initialize a variable which is going to has an object later.

Null, is a special one, because if you check its type with the typeof operator, it's going to return object.

All of these have two things in common:

  • They are immutable: they cannot change. If you change them, you are just creating a new one.
  • They don't have any methods or properties.

If primitive datatypes don't have methods or properties, then, why can we use string.toUppercase()? or any of the other methods that primitives have.

This is possible because some of the primitives have their equivalent in the objects world. That means that we use string type when we declare a string, but we use String object when we use some of the methods or properties on it.

Another question that you may have is how or when is the string converted to an object.

This is related with how the engine works.

The engine, "wraps" the primitive datatype into its equivalent object.

Finally, why don't keep it simple and just use objects everywhere? Smart question. We'll talk about it later. Let's discuss objects first.

Objects

Everything else, such as functions or arrays, are objects.

We've already talked about differences between objects and primitives. But there is one more. This one is quite more advanced, but it's also important in order to have a good understanding of how JavaScript actually works.

Memory

Let's go back to that question about why we use primitives instead of having everything as an object.

The answer is: because of how memory is handled.

JavaScript uses two kinds of memories: Memory Heap and Memory Stack.

Memory Stack, is where primitives are saved. This memory is smaller, but it's faster than Memory Heap. On the other hand, Memory Heap is bigger, but slower.

So what JavaScript does is that it saves primitives and a reference to objects into the Memory Stack and saves the complete object into the Memory Heap.

That's why we cannot copy objects that easy in JavaScript.

const obj = {
	string: 'primitive',
	array: 'object',
}

const objCopy = obj
objCopy.number = 'primitive'

console.log(obj) // {string: "primitive", array: "object", number: "primitive"}
console.log(objCopy) // {string: "primitive", array: "object", number: "primitive"}

Give it a shot in the console and you'll see it.

Since we are just copying a reference, both variables point to the same object.

To avoid this behavior, you can use the spread operator.

const obj = {
	string: 'primitive',
	array: 'object',
}

const objCopy = { ...obj }
objCopy.number = 'primitive'

console.log(obj) // {string: "primitive", array: "object"}
console.log(objCopy) // {string: "primitive", array: "object", number: "primitive"}