DEV Community

Gnio
Gnio

Posted on

ELI5: Functions vs. Class/Constructor in Javascript

Hello everyone,

I trust my post finds you well and healthy.

I'm not a posting person, but I'm tired of trying to understand in simple terms what is the difference between Function and Constructor in Javascript. And also, Class?.

Every time I find an article about it, explains by starting that 'Classes in Javascript are not like any other language, and is just for syntax.' or 'Javascript doesn't really have Classes, like Java'.

The thing is, I don't know Java, or C, or any other language. So I don't understand the reference, or what really does that mean. My only reference to Classes is CSS. That what it comes to my mind.

More to that, I recently stumble upon Constructor on FreeCodeCamp. Another topic I've been trying to understand but can't find simple way to explain it. An article in CSS-Tricks 'understanding Javascript constructors' starts: "Having a good understanding of constructors is crucial to truly understand the JavaScript language."

*newbie feeling intensified

And then it drops this:
"Constructors are like regular functions, but we use them with the new keyword. ".

What? If they are the same, why should I really learn this? Why is it crucial? Then the article goes on with jargons of things I can't really comprehend as a newbie in a programming language. And without a 'big word alert'.

Can someone please try to explain me this or tell me where I can find explanation? I already tried the big ones (mozilla, w3c schools, eloquent javascript, css-tricks).

If you took the time to read this, I love you already.

Thank you all in advance and stay safe.

Top comments (11)

Collapse
 
adrianmarkperea profile image
Adrian Perea • Edited

I'll give you the low-down on classes in JavaScript and classes in traditional OOP languages, say Python.

Traditional OOP languages

In traditional OOP languages, a class is a blueprint for objects. In terms of information management, the class is used to provide a) abstraction (which information is relevant? which is irrelevant?) and b) encapsulation (how do I hide/show what is relevant/irrelevant?). Through a class, I can create multiple implementations of this blueprint. These implementations are called instances. Each instance gets a copy of the methods and instance variables of the class.

class Person:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    def print_full_name(self):
        print(f'{self.first_name} {self.last_name}') # Adrian Perea        

person_a = Person('Adrian', 'Perea')
person_b = Person('G', 'Nio')

person_a.print_full_name() # Adrian Perea
person_b.print_full_name() # G Nio
Enter fullscreen mode Exit fullscreen mode

In this example, person_a and person_b are instances of the blueprint (read: class) Person. Each of them gets its own first_name and last_name instance variables, and print_full_name method.

JavaScript

Now JavaScript, while seemingly does the same thing, does this differently. Whenever we use the new keyword to execute a function, we create an implicit object that we can reference with this inside the function. Furthermore, objects created with a constructor function have a reference to the constructor function inside their own prototypes. That was a lot. Let's try to unpack this with code.

Let's first make an object without any fancy constructor functions:

function Person(first_name, last_name) {
    return {
        first_name,
        last_name,
        fullName() {
            console.log(`${this.first_name} ${this.last_name}`)
        }
    }
}

const person_a = Person('Adrian', 'Perea')
const person_b = Person('G', 'Nio')

peron_a.fullName() // Adrian Perea
person_b.fullName() // G Nio
Enter fullscreen mode Exit fullscreen mode

This works fully well. Why not call it a day and be done with it?
The brutally honest truth is, we can call it a day and be done with it. There are a lot of use cases that you can accomplish by just creating objects this way. But just because we can, doesn't mean we should, especially if there are arguably better ways of accomplishing the same thing. If we proceed with this route, we're not taking advantage of the prototypical inheritance that makes JavaScript unique (not necessarily better nor worse).

Let's take a look at another way we can implement this:

function Person(first_name, last_name) {
    this.first_name = first_name;
    this.last_name = last_name;
}

Person.prototype.fullName = function() {
    console.log(`${first_name} ${last_name}`);
}

const person_a = new Person('Adrian', 'Perea');
const person_b = new Person('G', 'Nio');

person_a.fullName() // Adrian Perea
person_b.fullName() // G Nio
Enter fullscreen mode Exit fullscreen mode

As I mentioned earlier, there are two things that are happening whenever we use the new keyword.

  1. An implicit object is created and is referred to as this. So, when we do this.firstName or this.lastName, it's as if we're assigning properties to an empty object.

  2. Objects created with a constructor function have a reference to the constructor function inside their own prototypes. After creating the constructor function above and its instances, try to type the following in your browser console:

person_a.__proto__ === Person.prototype // true
Enter fullscreen mode Exit fullscreen mode

Whenever we create a new instance of the Person constructor function through the new keyword, a reference to the prototype object of the constructor function gets added to the __proto__ property of the object. Read that again. After that, read it one more time. This bit is important.

As opposed to traditional OOP languages, methods are not copied to each instance of the class. When we call person_a.fullName(), JavaScript climbs up the __proto__ properties of the instances until it finds a qualified name of fullName(). Therefore, the method fullName() lives completely inside the prototype of the constructor function. This provides performance benefits since the methods only have to be defined once (on the prototype). That is, person_a.fullName === person_b.fullName === Person.prototype.fullName.

This means that whatever we define on Person.prototype will be available to all instances of Person. So we can do something weird (in traditional OOP sense) like this:

Person.prototype.lastName = function() {
    console.log(this.lastName);
}

// Note that we did not recreate the objects here!
person_a.lastName() // Perea
person_b.lastName() // Nio
Enter fullscreen mode Exit fullscreen mode

I hope that this clears everything up. To summarize:

  • constructor functions do two things: create an implicit object that is referenced by this, and assign the __proto__ property of each instance as a reference to the prototype object of the constructor function
  • When a function is called on the instance, the prototype chain is climbed until a reference to the function is found
  • In traditional OOP, all instances have a copy of each method. There is no concept of prototype

I didn't include a bit about inheritance. But I think that this information is enough to get you to understand it on your own.

A note about ES6 "classes"

Syntactic sugar. It's quite cumbersome to write prototype for each method you want to share amongst instances (in addition to breaking encapsulation at the textual level). ES6 class syntax is just an easy way to store everything in one place, without having to mess with prototype and all of that jazz.

I hope this was helpful.

Cheers,
Adrian

Collapse
 
gnio profile image
Gnio

Thank you so much for taking the time to write this reply. As Daniel mentioned, this deserve its own post. I'm sorry I didn't reply before, but I live among persistent distractions and internet issues. Thank you so much. I'm reviewing it now!

Collapse
 
gnio profile image
Gnio

Years later this response have helped me so much. Thank you so much Adrian.

Collapse
 
danielkun profile image
Daniel Albuschat

Adrian, nice! 👍 I once read an entire book in order to learn what you just covered in this comment.
Feel free to paste this comment into a whole new post, since it sure is worth it's own post on DEV!

Collapse
 
adrianmarkperea profile image
Adrian Perea

Wow! Thanks for the nice comment, Daniel! Working on its own post right now. Look out for it!

Collapse
 
patarapolw profile image
Pacharapol Withayasakpunt • Edited

Trying to find differences between these might answer your question

  • Functions with function keyword
  • Arrow functions
  • Class constructor in ES5

It isn't always distinguishable between functions and class constructor... I have tried to distinguish these programmatically before -- github.com/patarapolw/any-serializ...

Collapse
 
gnio profile image
Gnio

Thanks for the link. Checking it out.

Thanks for taking the time to reply and sorry for the late response :D

Collapse
 
nestedsoftware profile image
Nested Software • Edited

This is not a direct answer to your question, but JavaScript is a very odd language with a lot of confusing quirks - probably because it was originally thrown together over literally just a few days. Over the years, people have tried to cover up these idiosyncrasies with additional syntax to make the language at least feel closer to something like Java or C#. Unfortunately, these similarities are rather superficial, so you have to be careful to really understand what's going on to avoid some common bugs that can arise from using the language in the same way that you would in Java or C#. In your position, as someone who doesn't know Java, C# or similar languages, that adds up to even more confusion...

So, what to do? My suggestion is to not worry too much about the details of this stuff right now. Learn from tutorials that focus on specific programming tasks, like creating and processing a form, or drawing things on the screen, or even basic math and data structure manipulations.

As time goes on and you learn how to do practical things, hopefully you will feel empowered to understand a bit more about how things work.

Collapse
 
gnio profile image
Gnio

Thanks. I've been told something similar from someone else. It just really bothers me to move on without really understanding what's going on. I think eventually I will have to. Thanks for taking the time to reply!

Collapse
 
tazeenmomin profile image
tazeenmomin • Edited

Learn the 'oops concepts' of JAVA, with practical examples .