I have an interesting question, what is the difference between the Prototype() pattern and the Constructor() pattern in JavaScript when creating objects?
How does one way and the other affect the attributes and functions of those objects?
Can I combine them to further optimize memory?
It is very common for new developers or developers who come from non-functional languages to get confused, and it is not for less, the concept of object orientation is quite particular in JavaScript.
prototypes
Almost all objects in JavaScript have a
prototipo
. A prototype is simply an object "within another", but not just any object, but a special object; within this object the properties are stored. When a property of an object (objeto.propiedad
) is requested, what happens is that it will start looking for it first in the object, if it is not there, it will look for it in the prototype, and so on in a chain.An interesting question is: if the object is empty and has a prototype, who does it belong to? The response is to the parent prototype:
Object.prototype
. Do a test with the following statement:What you will see in the console will be:
Object.prototype
. But if you do instead, youObject.prototypeOf(Object.prototype)
'll see that it printsnull
, becauseObject.prototype
it's the parent of all prototypes and obviously doesn't have a built-in prototype.The availability of "universal" methods such as
toString
and is due to this prototypevalueOf
. There are also objects that do not necessarily haveObject.prototype
, but insteadFunction.prototype
as is the case withisNaN
.builders
An interesting note is that it
Object.prototype
has a function calledconstructor
, this function is called when you make use ofnew
and returns an instance of the functionthis
associated with it. Likewise, each instance will have a prototype derived fromObject.prototipo
.Consider this example:
As you can see, even though it
constructor
has a prototype of type function, the instance of Car is assigned a prototype of type object.Exhibit
Banana/Gorilla Problem
I think Joe Armstrong could not have summed up the problem of heredity with a better analogy. But what does he mean by this? The answer is simple:
When working with classical inheritance, it is very common to do an initial design and as requirements change, refactor classes and hierarchies at the risk of breaking everything . Also, it's not modular, so what if you need class features
A
andC
but don't want to inherit all of its functionality? This is where composition becomes important .Functional inheritance or composition
The great Douglas Crockford talks about the "dangers of classical inheritance and this" in JavaScript. He discusses factory functions , which are functions that create objects and don't need the
this
. This "pattern" is widely used by "anti-class" JavaScript developers. For example:As we can see in the previous code, functional inheritance or composition is much more modular, it's like lego, you only use the pieces that you need to use. This type of inheritance is much easier to refactor.
Object.assign vs Object.create
When you use a constructor to create instances, you will often need to use
hasOwnPoperty
it to find out if an object has a certain property (and not look at the internal prototypes), which if you forget can make a logical error. The same goes for objects created usingObject.create
. On the other hand, creating objects by assigning new values to a prototypeObject.assign
avoids this inconvenience.Look at the following example:
Note: It can be emulated
Object.assign
usingObject.setPrototypeOf
.Performance
About performance I have no idea; however, I don't think it's a big deal most of the time unless you're creating a lot of objects (and I mean, a lot of objects). You can do a test to find out.