Najčešće JavaScript prototip zbunjuje ljude koji su tek počeli učiti JavaScript - pogotovo ako su iz pozadine C ++ ili Java.
U JavaScriptu nasljeđivanje djeluje malo drugačije u odnosu na C ++ ili Java. JavaScript nasljeđivanje je šire poznato kao „prototipsko nasljeđivanje“.
Stvari postaju teže razumljive kada se susretnete i class
u JavaScript-u. Nova class
sintaksa izgleda slično C ++ ili Javi, ali u stvarnosti djeluje drugačije.
U ovom ćemo članku pokušati razumjeti "prototipsko nasljeđivanje" u JavaScript-u. Također proučavamo novu class
sintaksu i pokušavamo shvatiti što je zapravo. Pa krenimo.
Prvo ćemo početi sa JavaScript funkcijom i prototipom stare škole.
Razumijevanje potrebe za prototipom
Ako ste ikad radili s JavaScript nizovima ili objektima ili nizovima, primijetili ste da postoji nekoliko metoda koje su prema zadanim postavkama dostupne.
Na primjer:
var arr = [1,2,3,4];arr.reverse(); // returns [4,3,2,1]
var obj = {id: 1, value: "Some value"};obj.hasOwnProperty('id'); // returns true
var str = "Hello World";str.indexOf('W'); // returns 6
Jeste li se ikad zapitali odakle potječu ove metode? Niste sami definirali ove metode.
Možete li definirati vlastite metode poput ove? Mogli biste reći da možete na ovaj način:
var arr = [1,2,3,4];arr.test = function() { return 'Hi';}arr.test(); // will return 'Hi'
To će raditi, ali samo za ovu varijablu tzv arr
. Recimo da imamo drugu varijablu koja se zove arr2
tada arr2.test()
će baciti pogrešku "TypeError: arr2.test nije funkcija".
Pa kako te metode postaju dostupne svakoj instanci niza / niza / objekta? Možete li stvoriti vlastite metode s istim ponašanjem? Odgovor je da. To trebate učiniti na ispravan način. Kao pomoć u tome, dolazi JavaScript prototip.
Pogledajmo prvo odakle dolaze ove funkcije. Razmotrite isječak koda u nastavku:
var arr1 = [1,2,3,4];var arr2 = Array(1,2,3,4);
Stvorili smo dva niza na dva različita načina: arr1
s literalima niza i arr2
s Array
funkcijom konstruktora. Obje su jednake jedna drugoj, s nekim razlikama koje za ovaj članak nisu bitne.
Sada dolazimo do funkcije konstruktora Array
- to je unaprijed definirana funkcija konstruktora u JavaScript-u. Ako otvorite alate za Chrome Developer i prijeđete na konzolu i upišete console.log(Array.prototype)
i pritisnete, enter
vidjet ćete nešto poput dolje:

Tamo ćete vidjeti sve metode o kojima smo se pitali. Dakle, sada dolazimo odakle dolaze te funkcije. Slobodno pokušajte s String.prototype
i Object.prototype
.
Stvorimo vlastitu jednostavnu funkciju konstruktora:
var foo = function(name) { this.myName = name; this.tellMyName = function() { console.log(this.myName); }}
var fooObj1 = new foo('James');fooObj1.tellMyName(); // will print Jamesvar fooObj2 = new foo('Mike');fooObj2.tellMyName(); // will print Mike
Možete li prepoznati temeljni problem s gornjim kodom? Problem je što trošimo memoriju gore navedenim pristupom. Napominjemo da je metoda tellMyName
jednaka za svaki primjerak foo
. Svaki put kada stvorimo primjerak foo
metode na tellMyName
kraju zauzme prostor u memoriji sustava. Ako tellMyName
je isti za sve instance, bolje ga je držati na jednom mjestu i učiniti da se sve naše instance odnose na to mjesto. Pogledajmo kako to učiniti.
var foo = function(name) { this.myName = name;}
foo.prototype.tellMyName = function() { console.log(this.myName);}
var fooObj1 = new foo('James');fooObj1.tellMyName(); // will print Jamesvar fooObj2 = new foo('Mike');fooObj2.tellMyName(); // will print Mike
Provjerimo razliku gore navedenim pristupom i prethodnim pristupom. S gornjim pristupom, ako console.dir()
instancije vidite nešto slično:

Imajte na umu da kao svojstvo instanci imamo samo myname
. tellMyName
definirano je pod __proto__
. Doći ću do ovoga __proto__
nakon nekog vremena. Najvažnije je napomenuti da se usporedbom tellMyName
obje instance ocjenjuje s točnošću. Usporedba funkcija u JavaScript-u procjenjuje istinitost samo ako su njihove reference iste. To dokazuje da tellMyName
ne troši dodatnu memoriju za više instanci.
Idemo vidjeti isto s prethodnim pristupom:

Imajte na umu da je ovo vrijeme tellMyName
definirano kao svojstvo instanci. Nije više pod tim __proto__
. Također imajte na umu da ovaj put uspoređivanje funkcija ocjenjuje s lažnim. To je zato što se nalaze na dva različita memorijska mjesta i njihove reference su različite.
Nadam se da ste do sada shvatili potrebu za prototype
.
Sada ćemo pogledati neke detalje o prototipu.
Svaka JavaScript funkcija imat će prototype
svojstvo tipa objekta. Možete definirati vlastita svojstva pod prototype
. Kada ćete funkciju koristiti kao konstruktorsku funkciju, sve će njezine instance naslijediti svojstva od prototype
objekta.
Ajmo sada na to __proto__
imanje koje ste vidjeli gore. __proto__
Je jednostavno referenca na prototip objekta od kojih je instanca je naslijedila. Zvuči komplicirano? Zapravo nije toliko komplicirano. Zamislimo to na primjeru.
Razmotrite donji kod. Već znamo da će stvaranje niza s literalima niza naslijediti svojstva Array.prototype
.
var arr = [1, 2, 3, 4];
Ono što sam rekao gore je „ je jednostavno referenca na prototip objekta od kojih je instanca je naslijedila ”. Tako bi trebalo biti i sa . Provjerimo ovo.__proto__
arr.__proto__
Array.prototype

Sada ne bismo trebali pristupiti prototipu objekta pomoću __proto__
. Prema MDN-u, upotreba __proto__
je vrlo obeshrabrena i možda neće biti podržana u svim preglednicima. Ispravan način za to:
var arr = [1, 2, 3, 4];var prototypeOfArr = Object.getPrototypeOf(arr);prototypeOfArr === Array.prototype;prototypeOfArr === arr.__proto__;

The last line of the above code snippet shows that __proto__
and Object.getPrototypeOf
return the same thing.
Now it’s time for a break. Grab a coffee or whatever you like and try out the examples above on your own. Once you are ready, come back to this article and we will then continue.
Prototype chaining & Inheritance
In Fig: 2 above, did you notice that there is another __proto__
inside the first __proto__
object? If not then scroll up a bit to Fig: 2. Have a look and come back here. We will now discuss what that is actually. That is known as prototype chaining.
In JavaScript, we achieve Inheritance with the help of prototype chaining.
Consider this example: We all understand the term “Vehicle”. A bus could be called as a vehicle. A car could be called a vehicle. A motorbike could be called a vehicle. Bus, car, and motorbike have some common properties that's why they are called vehicle. For example, they can move from one place to another. They have wheels. They have horns, etc.
Again bus, car, and motorbike can be of different types for example Mercedes, BMW, Honda, etc.

In the above illustration, Bus inherits some property from vehicle, and Mercedes Benz Bus inherits some property from bus. Similar is the case for Car and MotorBike.
Let's establish this relationship in JavaScript.
First, let's assume a few points for the sake of simplicity:
- All buses have 6 wheels
- Accelerating and Braking procedures are different across buses, cars, and motorbikes, but the same across all buses, all cars, and all motorbikes.
- All vehicles can blow the horn.
function Vehicle(vehicleType) { //Vehicle Constructor this.vehicleType = vehicleType;}
Vehicle.prototype.blowHorn = function () { console.log('Honk! Honk! Honk!'); // All Vehicle can blow Horn}
function Bus(make) { // Bus Constructor Vehicle.call(this, "Bus"); this.make = make}
Bus.prototype = Object.create(Vehicle.prototype); // Make Bus constructor inherit properties from Vehicle Prototype Object
Bus.prototype.noOfWheels = 6; // Let's assume all buses have 6 wheels
Bus.prototype.accelerator = function() { console.log('Accelerating Bus'); //Bus accelerator}
Bus.prototype.brake = function() { console.log('Braking Bus'); // Bus brake}
function Car(make) { Vehicle.call(this, "Car"); this.make = make;}
Car.prototype = Object.create(Vehicle.prototype);
Car.prototype.noOfWheels = 4;
Car.prototype.accelerator = function() { console.log('Accelerating Car');}
Car.prototype.brake = function() { console.log('Braking Car');}
function MotorBike(make) { Vehicle.call(this, "MotorBike"); this.make = make;}
MotorBike.prototype = Object.create(Vehicle.prototype);
MotorBike.prototype.noOfWheels = 2;
MotorBike.prototype.accelerator = function() { console.log('Accelerating MotorBike');}
MotorBike.prototype.brake = function() { console.log('Braking MotorBike');}
var myBus = new Bus('Mercedes');var myCar = new Car('BMW');var myMotorBike = new MotorBike('Honda');
Allow me to explain the above code snippet.
We have a Vehicle
constructor which expects a vehicle type. As all vehicles can blow their horns, we have a blowHorn
property in Vehicle
's prototype.
As Bus
is a vehicle it will inherit properties from Vehicle
object.
We have assumed all buses will have 6 wheels and have the same accelerating and braking procedures. So we have noOfWheels
, accelerator
and brake
property defined in Bus
’s prototype.
Similar logic applies for Car and MotorBike.
Let’s go to Chrome Developer Tools -> Console and execute our code.
After execution, we will have 3 objects myBus
, myCar
, and myMotorBike
.
Type console.dir(mybus)
in the console and hit enter
. Use the triangle icon to expand it and you will see something like below:

Under myBus
we have properties make
and vehicleType
. Notice the value of __proto__
is prototype of Bus
. All the properties of its prototype are available here: accelerator
, brake
, noOfWheels
.
Now have a look that the first __proto__
object. This object has another __proto__
object as its property.
Under which we have blowHorn
and constructor
property.
Bus.prototype = Object.create(Vehicle.prototype);
Remember the line above? Object.create(Vehicle.prototype)
will create an empty object whose prototype is Vehicle.prototype
. We set this object as a prototype of Bus
. For Vehicle.prototype
we haven’t specified any prototype so by default it inherits from Object.prototype
.
Let’s see the magic below:

We can access the make
property as it is myBus
's own property.
We can access the brake
property from myBus
's prototype.
We can access the blowHorn
property from myBus
's prototype’s prototype.
We can access the hasOwnProperty
property from myBus
's prototype’s prototype’s prototype. :)
This is called prototype chaining. Whenever you access a property of an object in JavaScript, it first checks if the property is available inside the object. If not it checks its prototype object. If it is there then good, you get the value of the property. Otherwise, it will check if the property exists in the prototype’s prototype, if not then again in the prototype’s prototype’s prototype and so on.
So how long it will check in this manner? It will stop if the property is found at any point or if the value of __proto__
at any point is null
or undefined
. Then it will throw an error to notify you that it was unable to find the property you were looking for.
This is how inheritance works in JavaScript with the help of prototype chaining.
Feel free to try the above example with myCar
and myMotorBike
.
As we know, in JavaScript everything is an object. You will find that for every instance, the prototype chain ends with Object.prototype
.
The exception for the above rule is if you create an object with Object.create(null)
var obj = Object.create(null)
With the above code obj
will be an empty object without any prototype.

For more information on Object.create
check out the documentation on MDN.
Can you change the prototype object of an existing object? Yes, with Object.setPrototypeOf()
you can. Check out the documentation in MDN.
Want to check if a property is the object’s own property? You already know how to do this.Object.hasOwnProperty
will tell you if the property is coming from the object itself or from its prototype chain. Check out its documentation on MDN.
Note that __proto__
also referred to as [[Prototype]]
.
Sad je vrijeme za još jedan predah. Kad budete spremni, vratite se ovom članku. Zatim ćemo nastaviti i obećavam da je ovo zadnji dio.
Razumijevanje nastave u JavaScript-u
Prema MDN-u:
JavaScript klase, uvedene u ECMAScript 2015, prvenstveno su sintaksički šećer nad postojećim JavaScript nasljeđivanjem zasnovanim na JavaScriptu. Sintaksa klase ne uvodi novi objektno orijentirani model nasljeđivanja u JavaScript.Predavanja u JavaScript-u pružit će bolju sintaksu kako bismo postigli ono što smo gore učinili na mnogo čišći način. Prvo pogledajmo sintaksu razreda.
class Myclass { constructor(name) { this.name = name; } tellMyName() { console.log(this.name) }}
const myObj = new Myclass("John");
constructor
metoda je posebna vrsta metode. Automatski će se izvršiti svaki put kada izradite instancu ove klase. Unutar tijela vašeg razreda. constructor
Moguća je samo jedna pojava .
The methods that you will define inside the class body will be moved to the prototype object.
If you want some property inside the instance you can define it in the constructor, as we did with this.name = name
.
Let’s have a look into our myObj
.

Note that we have the name
property inside the instance that is myObj
and the method tellMyName
is in the prototype.
Consider the code snippet below:
class Myclass { constructor(firstName) { this.name = firstName; } tellMyName() { console.log(this.name) } lastName = "lewis";}
const myObj = new Myclass("John");
Let’s see the output:

See that lastName
is moved into the instance instead of prototype. Only methods you that you declare inside the Class body will be moved to prototype. There is an exception though.
Consider the code snippet below:
class Myclass { constructor(firstName) { this.name = firstName; } tellMyName = () => { console.log(this.name) } lastName = "lewis";}
const myObj = new Myclass("John");
Output:

Note that tellMyName
is now an arrow function, and it has been moved to the instance instead of prototype. So remember that arrow functions will always be moved to the instance, so use them carefully.
Let’s look into static class properties:
class Myclass { static welcome() { console.log("Hello World"); }}
Myclass.welcome();const myObj = new Myclass();myObj.welcome();
Output:

Static properties are something that you can access without creating an instance of the class. On the other hand, the instance will not have access to the static properties of a class.
So is static property a new concept that is available only with the class and not in the old school JavaScript? No, it’s there in old school JavaScript also. The old school method of achieving static property is:
function Myclass() {}Myclass.welcome = function() { console.log("Hello World");}
Now let’s have a look at how we can achieve inheritance with classes.
class Vehicle { constructor(type) { this.vehicleType= type; } blowHorn() { console.log("Honk! Honk! Honk!"); }}
class Bus extends Vehicle { constructor(make) { super("Bus"); this.make = make; } accelerator() { console.log('Accelerating Bus'); } brake() { console.log('Braking Bus'); }}
Bus.prototype.noOfWheels = 6;
const myBus = new Bus("Mercedes");
We inherit other classes using the extends
keyword.
super()
will simply execute the parent class’s constructor. If you are inheriting from other classes and you use the constructor in your child class, then you have to call super()
inside the constructor of your child class otherwise it will throw an error.
We already know that if we define any property other than a normal function in the class body it will be moved to the instance instead of prototype. So we define noOfWheel
on Bus.prototype
.
Inside your class body if you want to execute parent class’s method you can do that using super.parentClassMethod()
.
Output:

The above output looks similar to our previous function based approach in Fig: 7.
Wrapping up
So should you use new class syntax or old constructor based syntax? I guess there is no definite answer to this question. It depends on your use case.
In this article, for the classes part I have just demonstrated how you can achieve prototypical inheritance classes. There is more to know about JavaScript classes, but that’s out of the scope of this article. Check out the documentation of classes on MDN. Or I will try to write an entire article on classes at some time.
If this article helped you in understanding prototypes, I would appreciate if you could applaud a little.
If you want me to write on some other topic, let me know in the responses.
You can also connect with me over LinkedIn.