loading...

Not everything is an object in JavaScript

mmartinezsoria profile image Maximo Martinez Soria ・3 min read

"Everything in JavaScript is an object" is a well known sentence that almost everyone have listened at least once. However, it happens that it's not correct at all.

In order to understand the differences between JavaScript datatypes, let's split them in 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, it's a string and that's it.

They 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 typeof operator, it's going to return object. This doesn't mean that null is an object at all. This is just a bug, which cannot be fixed because of backward compatibility.

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, How do we use to string.toUppercase() then? or another method that primitives have.

It happens that 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 try and use some 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 and it happens that 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. First, we need to discuss some things about objects.

Objects

Everything else, such as functions or arrays, is an object.

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 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 have everything as an object.

The answer is: because of how memory is handled.

JavaScript use two kind of memories: Memory Heap and Memory Stack.

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

So what JavaScript does is that it save 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, when we modify the copy, we modify both variables.

If you want to avoid this behaviour, 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"}

By the way, this is the best practice to copy objects and remember that you can do the same with arrays: [...arr].

Thanks for reading and don't forget to comment your thoughts below.

Posted on by:

mmartinezsoria profile

Maximo Martinez Soria

@mmartinezsoria

Electronics technician and software engineer with a deep knowledge on React and Vue and experienced in Laravel and Node.

Discussion

markdown guide
 

Thank you. This is helpful and useful.

 

Thank you for your comment😊

 
Sloan, the sloth mascot Comment marked as low quality/non-constructive by the community View code of conduct

Calling typeof null is a bug makes me think that you don't really know what are you talking about.
JavaScript was created to mimic Java. In Java null is an object so it made sense that type of null was an object too.

 

I understand your point. But null is a primitive value. This is supported by the official documentation: developer.mozilla.org/en-US/docs/W...

 

Being primitive isn't significant.

null is the value used to express that something has been set to refer to no existing object (as opposed to undefined which expresses that something has not been set).

As such, being of type object makes sense, since it is to be used where objects are used.

JavaScript use two kind of memories: Memory Heap and Memory Stack.

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

This is incorrect.

Javascript does not divide memory like this, although some implementations may.

An object value is exactly like a primitive value -- it is immutable.

What an object value does is to allow you to access properties, and it is those properties that are mutable -- the properties are not part of the object value, otherwise changing a property would make a === b no-longer true.

As to where and how the properties are stored, that is an implementation decision.

All I wrote is supported by the docs.

Mutability:
developer.mozilla.org/en-US/docs/G...

Memory:
developer.mozilla.org/en-US/docs/W...
developer.mozilla.org/en-US/docs/W...

And I quote:

  • “Objects are allocated in a heap”
  • “Mutable is a type of variable that can be changed. In JavaScript, only objects and arrays are mutable, not primitive values.”

You're reading some documentation for Mozilla, not Javascript.

Mutable is a type of variable that can be changed. In JavaScript, only objects and arrays are mutable, not primitive values.

This is obviously wrong, since objects and arrays are not variables.

Next you need to understand what mutability for objects and arrays means.

let a = { name: 'a' };
let b = { name: 'b' };
let c = a;

// This changes a property of a, but does not change the value of a.
// c === a remains true.
a.name = 'c';

// This changes the value of a, but does not change the properties of that value.
// c === a becomes false
a = b;

What this means is that the value of the object is immutable, but properties of an object may be mutable.

If you read the ecmacscript standard, you'll find exactly zero mention of 'heap' -- because this is an implementation detail, not part of the language.

ecma-international.org/publication...

I don't think that example is correct.
Just give it a try.

After a.name = 'c', c === a is still true.
Changes are applied to both variables, because they are just a reference.

On the other hand, I agree about ecmascript. But Mozilla is just a common implementation.

And btw, thank you for taking your time to contribute to the discussion. I find really interesting to know different points of view.

a.name = 'c'; does not change any variable.

That's why the variables are still the same.

There are no references involved.

 
  1. Being a primitive value has nothing to do with being of type 'object'. Belonging to a type is about how things are categorized, and is essentially arbitrary.
  2. Mozilla's documentation is not the standard for Javascript (ecmascript) - it talks about mozilla's implementation.

To understand javascript you need to look at the ecmascript standard.

ecma-international.org/publication...

 

btw, I don't really know what was the thinking at the beginning. I'm talking about how the language works nowadays.