Objektovo orientované programovanie v JavaScripte - vysvetlené na príkladoch

JavaScript nie je objektovo orientovaný jazyk založený na triedach. Stále však má spôsoby použitia objektovo orientovaného programovania (OOP).

V tomto tutoriále vysvetlím OOP a ukážem vám, ako ho používať.

Podľa Wikipédie triedne programovanie je

štýl objektovo orientovaného programovania (OOP), v ktorom sa dedí dedenie prostredníctvom definovania tried objektov, namiesto dedenia dedinstva iba prostredníctvom objektov

Najpopulárnejší model OOP je založený na triede.

Ale ako som už spomenul, JavaScript nie je klasifikovaný jazyk - je to jazyk založený na prototypoch.

Podľa dokumentu Mozilly:

Prototypový jazyk má pojem prototypový objekt, objekt používaný ako šablóna, z ktorej sa majú získať počiatočné vlastnosti nového objektu.

Pozrite sa na tento kód:

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

Objektová premenná namesmá iba dve vlastnosti - fnamea lname. Vôbec žiadne metódy.

Odkiaľ teda hasOwnPropertypochádza?

No vychádza z Objectprototypu.

Skúste prihlásiť obsah premennej do konzoly:

console.log(names); 

Keď rozbalíte výsledky v konzole, získate toto:

Všimnite si poslednú vlastnosť - __proto__? Skúste to rozšíriť:

Pod Objectkonštruktorom uvidíte množinu vlastností . Všetky tieto vlastnosti pochádzajú z globálneho Objectprototypu. Ak sa pozriete pozorne, všimnete si tiež naše skryté hasOwnProperty.

Inými slovami, všetky objekty majú prístup k Objectprototypu. Nemajú tieto vlastnosti, ale je im udelený prístup k vlastnostiam v prototype.

__proto__vlastnosť

To ukazuje na objekt, ktorý sa používa ako prototyp.

Toto je vlastnosť každého objektu, ktorá mu poskytuje prístup k tejto Object prototypevlastnosti.

Každý objekt má túto vlastnosť predvolene, ktorá odkazuje na Object Protoypeokrem prípadov, keď je nakonfigurované inak (to znamená, keď je objekt __proto__namierený na iný prototyp).

Úprava __proto__nehnuteľnosti

Túto vlastnosť je možné upraviť výslovným vyhlásením, že by mala odkazovať na iný prototyp. Na dosiahnutie tohto cieľa sa používajú nasledujúce metódy:

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); 

V konzole by ste mali toto:

Všimli ste si __proto__vlastnosť a speakmetódu?

Object.create použije argument, ktorý mu bol odovzdaný, aby sa stal prototypom.

new kľúčové slovo

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__ property is directed to DogObject's prototype. But remember, DogObject's prototype is an object (key and value pair), hence it also has a __proto__ property which refers to the global Object protoype.

This technique is referred to as PROTOTYPE CHAINING.

Note that: the new keyword approach does the same thing as Object.create() but only makes it easier as it does some things automatically for you.

And so...

Every object in Javascript has access to the Object's prototype by default. If configured to use another prototype, say prototype2, then prototype2 would also have access to the Object's prototype by default, and so on.

Object + Function Combination

You are probably confused by the fact that DogObject is a function (function DogObject(){}) and it has properties accessed with a dot notation. This is referred to as a function object combination.

When functions are declared, by default they are given a lot of properties attached to it. Remember that functions are also objects in JavaScript data types.

Now, Class

JavaScript introduced the class keyword in ECMAScript 2015. It makes JavaScript seem like an OOP language. But it is just syntatic sugar over the existing prototyping technique. It continues its prototyping in the background but makes the outer body look like OOP. We'll now look at how that's possible.

The following example is a general usage of a class in JavaScript:

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); 

This is the result in the console:

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.

Preto obyčajné zvieratá majú prístup len ku animalConstructorale mačky majú prístup k catConstructora animalConstructor.

Balenie

JavaScript využíva svoju prototypovú povahu na vítanie vývojárov OOP vo svojom ekosystéme. Poskytuje tiež jednoduché spôsoby vytvárania prototypov a usporiadania súvisiacich údajov.

Pravé jazyky OOP nevytvárajú prototypy na pozadí - jednoducho si to všimnite.

Veľké poďakovanie patrí kurzu Will Sentance na Frontend Masters - JavaScript: Tvrdé časti objektovo orientovaného JavaScriptu. Z jeho kurzu som sa dozvedel všetko, čo v tomto článku vidíte (plus malý prieskum navyše). Mali by ste to skontrolovať.

Ak máte akékoľvek otázky alebo príspevky, môžete ma kontaktovať na Twitteri na adrese iamdillion.

Vďaka za prečítanie : )

Užitočné zdroje

  • Objektovo orientovaný JavaScript pre začiatočníkov
  • Úvod do objektovo orientovaného programovania v JavaScripte