Let's dive deeper into how javascript 'class' objects really function under the hood. There are many quirks in the js language in its creation and handling of objects, and especially if you're used to a different language that was strongly 'object oriented' (like me), this can get very, very confusing. There are some clever methods that have become standard js design patterns to mimick how OOP languages function, but there are some key differences in its inherent mechanism worth highlighting that separate it from the classic OOP paradigm - they're worth looking into not only for avoiding mistakes, but also leveraging its strengths into better and best practices.
Here is the new ES6 'class' constructor in action..
You can see how I tried creating a changeLastName() method inside the class, but that method were not created at all in the instantiated objects of that class, so when I tried to access that function through it, I ran into a TypeError. To create new methods that would propagate to the instantiated objects, I had to add prototype
- Employee.prototype.changeLastName
. Only then was I able to create a method that could be invoked with instances of that class.
The strange thing is that my first attempt did indeed create a method within the class, which I was then able to invoke via the class name. It did not change the properties of all its instance objects though.. what it did actually, was create a separate property within that class that were not inherited by its instance objects.
So what is happening here!? Well this demonstrates how the 'class' object is not really a 'class' in the classic sense. It is an object like any other, that also functions as a constructor. It can have separate properties/methods of its own like any object.
'Class' definition in js encapsulates these two things: constructor, and prototype.
Whenever you define a function, it gets an automatically created property called prototype. The prototype property points to a special "prototype" object, which is also automatically created with each function. It is THAT object that contains all the shared "members" for your "class." (link)
In other languages a class is a single thing, but "class" definitions in JavaScript are split into TWO PARTS:
1. The constructor (a plain old function), such as Employee
2. The prototype, an automatically created object that every function gets.
So a "class" is actually TWO separate objects! (link)
In more "sane" object-oriented languages, you create a class, you spawn objects off of them, and you're done with it. If you need to make a global change you do it at the class level, and all instantiated objects pick up that change automatically. But JavaScript is NOT a "sane" object-oriented language. ~Steve Kwan
The key takeaway is that prototypes don’t define a type; they are themselves instances and they’re mutable at runtime, with all that implies and entails. ~Justen Robertson
For a deep dive into this topic, check out As a JS Developer, This Is What Keeps Me Up at Night. The developer is of the opinion that ES6 with its 'class' designation just muddied the waters with "syntactic obscurantism. It tries to hide the prototypical inheritance model and the clumsy idioms that come with it, and it implies that JavaScript is doing something that it is not." Pop Quiz from the seasoned full-stack developer:
When a method you're invoking does not exist in the instantiated object itself, the engine will search for it in its prototype object and invoke it if it exists. But if you create a method that shares the same name in the instantiated object itself, that method will henceforth become the one that is invoked, until it is deleted.
img source
When you define constructor methods, it is copied for every instance of that class whereas for prototype methods, the instances just 'reference' its prototype object method. Changing prototype properties would change it for every instance of that class/prototype.
Some advantages of using prototypal inheritance includes that it minimizes memory usage!
As we observed above, it is possible to create class methods that belong to the class object itself, as opposed to the prototype. These are called static
methods - they refer to methods that can be called directly from the class, that do not need instantiation of the class. (You cannot call a static method by the instance object, but only through the class object itself.) To access non-static methods, however, you need an instance object of that class.
static
methods belong and operate on the class (object) level, so should be reserved to define functions for that class as a whole. You can use the static
keyword to differentiate it from prototype
methods.
Here a class method is used to compare two instance objects:
An exploration of JavaScript's prototype and constructor properties
Constructors considered mildly confusing
Javascript Constructor/Prototype Patterns
Deep Dive: Understanding Constructor and Prototype
__