Unlike most other OO languages ( Java , C # ), the object system in JavaScript is based on prototypes, not classes. Classes that you know from languages such as Java do not technically exist in JavaScript ( JS ).
The entire hierarchy of objects is built on chains - prototypes. Object.prototype is an object from which all other objects are "inherited". It contains methods such as toString() or valueOf(). Its prototype is null . I note that Object is just a constructor function for creating objects:
typeof Object // 'function' Object.prototype // объект Object {} Object.prototype.__proto__ // 'null'
prototype , which is used in the example, is applicable only to functions, and __proto__ (or [[Prototype]] ) is used for the created objects.
For example, Array :
typeof Array // 'function' Array.prototype.__proto__ === Object.prototype // true var arr = [1,3] arr.__proto__ // [] arr.__proto__ === Array.prototype // true arr.__proto__.__proto__ // объект Object {} arr.__proto__.__proto__ === Object.prototype // true
All array methods ( slice() , splice() ) are stored in the Array.prototype object, and the prototype of this object is located on the Object.prototype .
It turns out: arr -> Array.prototype -> Object.prototype -> null
Also with other built-in constructor functions, such as Function , Date , Number , etc.
Now everything is complicated by the fact that in the new standard (ES6) the JS developers introduced the class - a convenient “syntactic sugar” for specifying the designer together with the prototype. As far as I know, he was introduced, including specifically for developers who want to write in JS , but who are embarrassed that they do not have classes :). In fact, the class in JS is a regular function:
class Car {} typeof Car // 'function'
Therefore, I still think that the concept of class and classical inheritance is a bit incorrect in relation to JS.
One of the advantages of prototype inheritance is probably flexibility. A class (for example in Java ) defines all properties for all its instances. Cannot add properties dynamically at run time. At the same time, in JS , the constructor function defines the initial set of properties. You can add or remove properties dynamically for individual objects or all at once.
Perhaps after using interfaces / abstract classes in Java, this will seem not a plus, but a minus, but if you know how to use it, then you will not get it in other languages.
// Функция конструктор function Calculator () {} Calculator.prototype.max = function (a, b) { return Math.max(a, b); } // Создадим два экземпляра (объекта) var ins1 = new Calculator(); var ins2 = new Calculator(); // Протестируем метод max: console.log(ins1.max(1, 5), ins2.max(1, 5)); // -> 5, 5 // Изменим метод прототипа, чтобы можно было выбирать макс. значение // передавая сколько угодно параметров Calculator.prototype.max = function () { var args = Array.prototype.slice.apply(arguments); return Math.max.apply(null, args); } // Протестируем опять: console.log(ins1.max(1, 5), ins2.max(1, 5)); // -> 5, 5 console.log(ins1.max(9, -5, 13), ins2.max(9, -5, 13)); // -> 13, 13
We could also change the implementation for only one object (to make it as necessary as part of the task).
Again, the prototype used in the example applies only to functions, and __proto__ (or [[Prototype]] ) is used for the created objects. The max method will be in the prototype of the created objects ( ins1.__proto__.max ), and their prototypes point to the same object:
ins1.__proto__ === ins2.__proto__ // true
An interesting point:
ins1.__proto__ // объект прототип ins1.__proto__.constructor // function Calculator () {} - функция, с помощью который создаются объекты ins1.__proto__.constructor.prototype // объект, который является прототипом // Проверим? ins1.__proto__.constructor.prototype === ins1.__proto__ // true
Other advantages that can be noted are: simplicity, power of this approach, less redundant code, dynamism.
If you are interested in the moment, why prototype inheritance in JS is similar to the classical one (by syntax, for example, using the new operator), then this is easy to explain. The creator of JS , Brendan Eich , wanted JavaScript to become the younger brother of Java and tried to make it as similar as possible syntactically.
In general, I hope that you are not even more confused, you just need to study to study and study again :)
UPD .:
An example of using "classes" from the standard ES6 .
class Auto { constructor(options) { this.name = options.name; } getName() { return this.name; } } const car = new Auto({ name: 'Lightning McQueen' }); car.getName(); // 'Lightning McQueen'
All methods declared in the "class" are automatically placed in the prototype of the created objects, and the fields in the object itself.
car.__proto__.getName // function getName() {return this.name;} car.__proto__.name // undefined car.__proto__.constructor // Auto car.name // 'Lightning McQueen'
Well, Auto prototype prototype will link to Object.prototype
car.__proto__.__proto__ === Object.prototype // true
Auto "class" code (without methods) in the ES5 standard will look like this:
'use strict'; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Auto = function Auto(options) { _classCallCheck(this, Auto); this.name = options.name; };
A regular constructor function with a check (by calling _classCallCheck ) so that Auto cannot be called as a function. This is still a class :)
Auto() // Uncaught TypeError: Cannot call a class as a function(…)
Object.defineProperty used to create methods, and you can see how the transpiler works for methods (translates code from ES6 to ES5 and not only) here: https://babeljs.io/repl/ ( Babel is one of the most popular transpilers).
I recommend to read:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model
- https://learn.javascript.ru/prototype
HelloWorld.prototype.sayHi()), we are not sayingstatic(class HelloWorld {public function () {}}), ... - Roman GrinyovHelloWorld.sayHi()), then we saystatic(class HelloWorld {public static function () {}}). Something like that ... I guess. - Roman Grinyov