Over the time I've worked with the JavaScript language, I've used different ways to create objects through what could properly be the emulation of a class (or object literal).
The forms I have worked with are the following:
Closures :
var NombreClase = (function () { function NombreClase () {} NombreClase.prototype.metodo = function () { // código } NombreClase.metodoEstático = function () { // código } function metodoPrivado () { // código } return NombreClase; })();
Prototype (
prototype
) :function NombreClase (arg1, arg2) { this.arg1 = arg1; this.arg2 = arg2; } NombreClase.prototype.metodo = function () { // código } NombreClase.metodoEstático = function () { // código }
Literal object :
var NombreClase = { prop: 'foo', metodo: function () { // body... } };
I would like to objectively know what is the best way to use it? Is there another way? And why is it recommended?
JavaScript's inheritance system doesn't work the same way as most languages that have proper classes. In javascript there are no classes, there are prototypes and these share similarities with the classes but they do not behave exactly like them.
The first most obvious difference between both types of inheritance is that in traditional classes they generate the model of the new object and take care of its initialization, that is, they have a constructor and define the methods that the created object will have. This is an example in C#
This definition of object attributes (read properties, methods, etc.) is conditioned both by the methods that are declared in the same class and in the parent classes and the visibility of said attributes can be controlled in the same class definition.
In javascript this works similarly but the radical difference is that the initialization code or constructor (read function) is the code that is inside the same class and the inheritance system is managed by the prototype. It is approximately the same result but the responsibilities are executed separately.
All properties are public and you have to resort to tricks to achieve encapsulation. It is also possible to create new properties in the execution of the same constructor
This has the disadvantage that there is now a different copy of the method for each object, so the prototype is used to make method creation more efficient since all instances share the same method.
As is evident, the language is very permissive and does not have a class design as is usually specified in object-oriented programming, so simulating a class has generated countless different implementations, all of them focused on compensating for the language's shortcomings.
Basically there are two ways to create a class and all the libraries that can be used will internally use one or the other method.
closure
As you can see, the prototype is not used anywhere and this has the immediate disadvantage that the operator
instanceof
stops working. Also creating methods in the constructor is less efficient as I mentioned earlier. The advantage is that usually in javascript you have to do things like thissetTimeout(hijo.imprime.bind(hijo), 1000)
because of the way the keyword worksthis
and in this case you can directly executesetTimeout(hijo.imprime, 1000)
.Prototype
This is the preferred variant and you will find many implementations that behave slightly differently but basically do something like this
As you can see the whole definition is radically different from the standard definition of a class as it is scattered and not very easy to reason about. The trick of this method is always to replace or modify the property
prototype
of the function (class) to establish an inheritance chain since in javascript when a property is referenced the interpreter looks in its prototype and in the prototype of its parent and so on until it reaches Object.prototype .Solutions always revolve around this mechanism. Here is node's implementation of util.inherits that uses the Object.create method to set the prototype. This has the peculiar feature of using a property
super_
to store a reference to the parent class for later use.ES6 classes
These classes are syntactic sugar on top of traditional javascript prototypical inheritance.
Much cleaner and easier to understand but it's still prototyping to the point where it's possible to inherit from a simple function
Here is a list of the most notable libraries that either implement OOP directly in javascript or compile to it
Well, I consider that all 3 are useful, the problem is that we are more comfortable when working.
closures
I feel comfortable working with these, since if we go to the design patterns it is easy to assemble a Modular Pattern . Allows easy reading of the code. The concepts of public and private functions are separated. and it is the closest thing to a class.
prototype
The prototype seems more basic to me, what makes it more powerful is the issue of being able to change a specific function without the need to modify the main object, the management of public and private functions becomes more complex.
Object
It is a simple object, you are not creating a class as such.
My recommendation is to work with Closures, since it is the closest thing to a class, if you work with object-oriented programming it will be easy to read and create them. With performance issues, I consider that it depends on the complexity that you give it, but I don't think there is much difference.
Create a native JavaScript class .
Among the many things it introduces, ECMAScript 6 includes definition of classes using the keyword
class
:If you're working with Node.js, the classes are available in the latest versions. In earlier versions they are available through the option
--harmony
.The problem usually comes from wanting to make use of these features in the browser, in which case it is recommended to use Babel , an ES6 to ES5 compiler that supports classes, among other things. Babel is also available for Node.js if your requirements include ES5 support.
In the 3rd case, a class is not being simulated since it simply has a single object with properties and functions.
In the 2nd, when assigning the functions to the prototype , the methods are defined in the prototype of the function, which means that there is a single copy of the methods for all the instances of the "class" , in a similar way as it is implemented in other idioms.
In the first case, not only is the above achieved, but since there is a closure, it is also possible to encapsulate private methods that have no scope outside the outermost function, which is the closest thing to a class .
Except for the private method this form is like TypeScript , which is a superset of JavaScript compiles its classes to JavaScript.
Typescript:
JavaScript:
I couldn't tell you which is the best or the worst way to create classes in Javascript, since it would become a topic of discussion given the preferences of a given programmer.
Regarding the performance issue, I don't know exactly what one or another way of creating the class infers, I would think that it is the same performance for any of them, what you really have to think about is the performance in the method call and obtaining data that changes very little, for example, a good practice is to implement a cache in javascript
Regarding the creation of classes in javascript, however
emules
the class is, I recommend that you create it inside containers/namespaces.I'm going to leave you as a reference this article JavaScript object-oriented programming that I found on the web, maybe there you will find the best way to create a class in javascripts.
If your code is going to scale so much that you need classes, my recommendation is that you stop thinking about it and start with
TypeScript
TypeScript is a superset of the javascript language that incorporates OOP and strong typing features. When generating a TypeScript project what results from the 'compilation' is simple high performance and functional standard javascript.
TypeScript already incorporates full support for ECMA Script 6 and has been adopted by the big players in the industry such as
and endless more
It is very easy to learn because being a superset you can continue using everything you already know about javascript .
TypeScript Walkthrough
examples
At Ceylon we use the second approach, the prototype one, but the constructor is a private function. We define a type like this:
To create an instance:
We made this design based on the book "JavaScript: The Good parts" by Douglas Crockford. Along with some additional mechanisms, it even allows us to implement multiple inheritance.
A good option is to use babeljs to be able to use es6/7 features such as classes.
https://babeljs.io/
this has been a very popular way of working lately and you can use babeljs together with webpack or browserify to compile and optimize all your code in a single buddle.
I have come to the conclusion that there are 3 good ways to do it. and created the following post on the subject:
http://ricardogeek.com/3-ways-to-define-classes-in-javascript/
I hope it helps you :)