Прототипное программирование — это модель ООП которая не использует классы, а вместо этого сначала выполняет поведение класса и затем использует его повторно (эквивалент наследования в языках на базе классов), декорируя (или расширяя) существующие объекты прототипы. (Также называемое бесклассовое, прототипно-ориентированное, или экземплярно- ориентированное программирование.) 

I ask for help in explaining this text .. I am trying to go parallel to the web, it is difficult to master the approach to Java Script after Java.

What is prototype programming?

" this is an OOP model that does not use classes, but instead first performs the behavior of the class " What ???

With the understanding of object-oriented programming, there are no problems.

  • 2
    where does this text come from? - Grundy
  • Perhaps a duplicate question: Interpretation of the word prototype in articles about js - Grundy Nov.
  • As I understood it, although maybe I didn’t understand it ... your classes are simply inherited from the base classes, and the base classes are inherited from their base classes and so far we don’t come to one / several classes that are not inherited from anyone. Tree ... At the same time, we can still inherit from other classes that will act as impurities ... By adding something to the prototype of the current class ( HelloWorld.prototype.sayHi() ), we are not saying static ( class HelloWorld {public function () {}} ), ... - Roman Grinyov
  • ... and if we just add in the class ( HelloWorld.sayHi() ), then we say static ( class HelloWorld {public static function () {}} ). Something like that ... I guess. - Roman Grinyov

3 answers 3

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:

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model
  2. https://learn.javascript.ru/prototype
  • I think I got confused :) - Grundy
  • "It is not possible to add properties dynamically at runtime. 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." - The advantage of JS prototypal inheritance vs classic inheritance is the ability to add prototypes dynamically and only? - Maks.Burkov
  • Added advantages in response, which I consider the most basic (I recommend reading the excellent answer about the advantages of prototype inheritance in js: stackoverflow.com/a/16872315/6554441 ). In general, these are different approaches for building a hierarchy of objects, as elsewhere, have their pros and cons. - saaaaaaaaasha
  • Nevertheless, the term "class" is quite applicable to JS and differs little from the usual OOP. If it is more convenient for people to think in classes - why refuse them such an opportunity, apply to JS? - Goncharov Alexander
  • @GoncharovAleksandr the term "class" is quite applicable, I agree. You can create "classes" using class Foo extends Bar {} constructions, and everything will work fine. But at the time of the study of prototypes in js and how they are arranged, it is better to ignore the concept of "classes" and the classical inheritance, so as not to be confused. - saaaaaaaaasha

Classical OOP and JS prototypes actually have few differences:

  1. Any function in JS (except for short - switch functions of ES6) is in OOP terminology a class: the new operator can be applied to any JS function, which makes it a constructor. This already expands the position of OOP in which objects construct not functions, but classes. Further, instead of the term function, I use the term class.

  2. The prototype is the ancestor class of the object, everything is like in OOP - the only difference is that the prototype in JS is already constructed “ready” object, and in the classical OOP “prototype” is inseparable from the descendant class itself: that is, neither an object, nor anything "physical". How inheritance in JS works, similar to normal OOP inheritance, is easy to understand by the following example:

 var classA = function(){this.x = function(){ this.a++; return this.a; } }; var classB = function(){ this.a = 2;}; classB.prototype = new classA(); console.log((new classB) instanceof classA); console.log((new classB).x()); 

  1. Unless prototypes can do more than classes can - for example, a prototype (ancestor class speaking OOP language) can be changed / set both for one object and for the class as a whole at runtime. For example, you can add type behavior (call through brackets) to type-number (Number), see crossing hedgehogs with hedgehogs in MDN . Where did you see that in the OOP it was possible to replace the ancestor class on the fly?) During the installation operation of the prototype - the same thing happens as if the base class were replaced: namely, all the properties / methods of the object that were not found in themselves - are already searched another ancestor class, logic changes. Actually this possibility of substitution / installation of the base class is the main feature of prototype programming.
  2. If you need to call the parent's class method, it is redefined in the current class: before ES6 (which has super ), you could do this.__proto__.someMethod.apply(this, [arg1, arg2]); . Longer than usual in the PLO - but the essence remains the same. Access to the parent constructor is also available through this.__proto__.constructor.apply(this,[...]) . I point to this - because not obvious at first - and the prototypes seem completely dull in terms of the PLO.
  3. ES6 and its class definition syntax are just decorations of good old prototypes: that is, there is nothing fundamentally new in it. Is that the PLO in JS has become more convenient. That is, IMHO - Прототипное программирование is just a motto. Well, yes - there is no protected , I also spat at first, and then I realized that I don’t need it: the encapsulation in JS is done very nicely on closures. But no one bothers to invent your own OOP if you really want to (I would not recommend it, but sometimes you will find it in frameworks), and also make mutant objects - for example, an array can be a function at the same time via setPrototypeOf .

How the prototypes are described in the books and manuals on JS is different: the answer describes a brief help for the analysis of prototypes for people who know other OOP languages.

  • It is necessary to digest, yet in Java everything looks clearer and more logical in my opinion .. - Maks.Burkov
  • @Maks.Burkov never mind this prototype programming term. The essence of the answer is that it differs little from OOP, it is slightly extended OOP, but without private / protected encapsulation. By the way, encapsulation in JS is supposed to be made through closure (nested functions) - which is much more powerful than private / protected. - Goncharov Alexander
  • @ Maks.Burkov slightly corrected the answer. Maybe something will clarify. Honestly, I was also very annoyed by all the material on JS prototypes after C ++, so this is the answer that was once looked for by myself - Goncharov Alexander
  • @GoncharovAleksandr, not any more, you cannot use the new operator to the switch functions - Grundy
  • @Grundy thanks, I will correct. - Goncharov Alexander

In my opinion, prototype programming is very easy to understand. You have a collection of objects and some of them inherit the properties or methods of others. That's all, there simply does not appear an extra entity "class".

"this is an OOP model that does not use classes, but instead first performs the behavior of the class" - and this is an incorrect translation of this fragment:

If you’re a little bit of a woman, you’ll be able to complete your life cycle.

However, here and in the original abstrusely written.