Objektno orijentirano programiranje u JavaScript-u - objašnjeno na primjerima

JavaScript nije objektno orijentirani jezik koji se temelji na klasama. Ali još uvijek ima načina za korištenje objektno orijentiranog programiranja (OOP).

U ovom uputstvu objasnit ću OOP i pokazati vam kako ga koristiti.

Prema Wikipediji, programiranje temeljeno na nastavi jest

stil Objektno orijentiranog programiranja (OOP) u kojem se nasljeđivanje događa definiranjem klasa objekata, umjesto nasljeđivanja koje se događa samo putem objekata

Najpopularniji model OOP-a temelji se na klasi.

Ali, kao što sam spomenuo, JavaScript nije klasificirani jezik - to je prototipski jezik.

Prema Mozilinoj dokumentaciji:

Jezik zasnovan na prototipu ima pojam prototipskog objekta, objekta koji se koristi kao predložak iz kojeg se dobivaju početna svojstva novog objekta.

Pogledajte ovaj kod:

let names = { fname: "Dillion", lname: "Megida" } console.log(names.fname); console.log(names.hasOwnProperty("mname")); // Expected Output // Dillion // false 

Objektna varijabla namesima samo dva svojstva - fnamei lname. Nikakvih metoda.

Pa odakle hasOwnPropertydolazi?

Pa, dolazi iz Objectprototipa.

Pokušajte prijaviti sadržaj varijable na konzolu:

console.log(names); 

Kada proširite rezultate u konzoli, dobit ćete ovo:

Primijetite posljednje svojstvo - __proto__? Pokušajte ga proširiti:

Ispod Objectkonstruktora vidjet ćete skup svojstava . Sva ta svojstva dolaze iz globalnog Objectprototipa. Ako dobro pogledate, primijetit ćete i naše skriveno hasOwnProperty.

Drugim riječima, svi objekti imaju pristup Objectprototipu '. Oni ne posjeduju ta svojstva, ali im se omogućuje pristup svojstvima u prototipu.

__proto__nekretnine

To upućuje na objekt koji se koristi kao prototip.

Ovo je svojstvo na svakom objektu koje mu omogućava pristup Object prototypevlasništvu.

Svaki objekt ima ovo svojstvo prema zadanim postavkama, koje se odnosi na Object Protoypeosim ako nije drugačije konfigurirano (odnosno kada je objekt __proto__usmjeren na drugi prototip).

Izmjena __proto__svojstva

Ovo se svojstvo može izmijeniti izričitim navodom da bi se trebalo odnositi na drugi prototip. Da bi se to postiglo koriste se sljedeće metode:

Object.create()

function DogObject(name, age) { let dog = Object.create(constructorObject); dog.name = name; dog.age = age; return dog; } let constructorObject = { speak: function(){ return "I am a dog" } } let bingo = DogObject("Bingo", 54); console.log(bingo); 

U konzoli biste imali ovo:

Primijetite __proto__svojstvo i speakmetodu?

Object.create koristi argument prosljeđen njemu da postane prototip.

new ključna riječ

function DogObject(name, age) { this.name = name; this.age = age; } DogObject.prototype.speak = function() { return "I am a dog"; } let john = new DogObject("John", 45); 

john„S __proto__nekretnina je usmjerena na DogObject” s prototipom. Ali imajte na umu, DogObjectprototip je objekt ( par ključ i vrijednost ), stoga također ima __proto__svojstvo koje se odnosi na globalni Objectprototip.

Ova tehnika naziva se PROTOTIP LANCANJEM .

Imajte na umu da:new pristup ključne riječi radi istu stvar kao i Object.create()već samo to čini lakše, jer se neke stvari automatski za vas.

I tako...

Svaki objekt u Javascriptu Objectprema zadanim postavkama ima pristup prototipu. Recimo prototype2, ako je konfiguriran za upotrebu drugog prototipa, tada prototype2bi prema zadanim postavkama također imao pristup prototipu Objekta, i tako dalje.

Kombinacija objekta i funkcije

Vjerojatno vas zbunjuje činjenica da DogObjectje funkcija ( function DogObject(){}) i ima svojstva kojima se pristupa točkovnim zapisom . To se naziva kombinacijom funkcionalnih objekata .

Kada se funkcije deklariraju, po defaultu im se dodjeljuje puno svojstava koja su im pridružena. Imajte na umu da su funkcije također objekti u JavaScript vrstama podataka.

Sad, Razred

JavaScript je uveo classključnu riječ u ECMAScript 2015. Čini da se JavaScript čini kao OOP jezik. Ali to je samo sintatički šećer u odnosu na postojeću tehniku ​​izrade prototipa. Nastavlja s prototipiranjem u pozadini, ali čini da vanjsko tijelo izgleda kao OOP. Sad ćemo pogledati kako je to moguće.

Sljedeći je primjer općenita upotreba a classu JavaScript-u:

class Animals { constructor(name, specie) { this.name = name; this.specie = specie; } sing() { return `${this.name} can sing`; } dance() { return `${this.name} can dance`; } } let bingo = new Animals("Bingo", "Hairy"); console.log(bingo); 

Ovo je rezultat u konzoli:

The __proto__ references the Animals prototype (which in turn references the Object prototype).

From this, we can see that the constructor defines the major features while everything outside the constructor (sing() and dance()) are the bonus features (prototypes).

In the background, using the new keyword approach, the above translates to:

function Animals(name, specie) { this.name = name; this.specie = specie; } Animals.prototype.sing = function(){ return `${this.name} can sing`; } Animals.prototype.dance = function() { return `${this.name} can dance`; } let Bingo = new Animals("Bingo", "Hairy"); 

Subclassing

This is a feature in OOP where a class inherits features from a parent class but possesses extra features which the parent doesn't.

The idea here is, for example, say you want to create a cats class. Instead of creating the class from scratch - stating the name, age and species property afresh, you'd inherit those properties from the parent animals class.

This cats class can then have extra properties like color of whiskers.

Let's see how subclasses are done with class.

Here, we need a parent which the subclass inherits from. Examine the following code:

class Animals { constructor(name, age) { this.name = name; this.age = age; } sing() { return `${this.name} can sing`; } dance() { return `${this.name} can dance`; } } class Cats extends Animals { constructor(name, age, whiskerColor) { super(name, age); this.whiskerColor = whiskerColor; } whiskers() { return `I have ${this.whiskerColor} whiskers`; } } let clara = new Cats("Clara", 33, "indigo"); 

With the above, we get the following outputs:

console.log(clara.sing()); console.log(clara.whiskers()); // Expected Output // "Clara can sing" // "I have indigo whiskers" 

When you log the contents of clara out in the console, we have:

You'll notice that clara has a __proto__ property which references the constructor Cats and gets access to the whiskers() method. This __proto__ property also has a __proto__ property which references the constructor Animals thereby getting access to sing() and dance(). name and age are properties that exist on every object created from this.

Using the Object.create method approach, the above translates to:

function Animals(name, age) { let newAnimal = Object.create(animalConstructor); newAnimal.name = name; newAnimal.age = age; return newAnimal; } let animalConstructor = { sing: function() { return `${this.name} can sing`; }, dance: function() { return `${this.name} can dance`; } } function Cats(name, age, whiskerColor) { let newCat = Animals(name, age); Object.setPrototypeOf(newCat, catConstructor); newCat.whiskerColor = whiskerColor; return newCat; } let catConstructor = { whiskers() { return `I have ${this.whiskerColor} whiskers`; } } Object.setPrototypeOf(catConstructor, animalConstructor); const clara = Cats("Clara", 33, "purple"); clara.sing(); clara.whiskers(); // Expected Output // "Clara can sing" // "I have purple whiskers" 

Object.setPrototypeOf is a method which takes in two arguments - the object (first argument) and the desired prototype (second argument).

From the above, the Animals function returns an object with the animalConstructor as prototype. The Cats function returns an object with catConstructor as it's prototype. catConstructor on the other hand, is given a prototype of animalConstructor.

Therefore, ordinary animals only have access to the animalConstructor but cats have access to the catConstructor and the animalConstructor.

Wrapping Up

JavaScript leverages its prototype nature to welcome OOP developers to its ecosystem. It also provides easy ways to creating prototypes and organize related data.

True OOP languages do not perform prototyping in the background - just take note of that.

A big thanks to Will Sentance's course on Frontend Masters - JavaScript: The Hard Parts of Object Oriented JavaScript. I learned everything you see in this article (plus a little extra research) from his course. You should check it out.

You can hit me up on Twitter at iamdillion for any questions or contributions.

Thanks for reading : )

Useful Resources

  • Object-oriented JavaScript for beginners
  • Introduction to Object Oriented Programming in JavaScript