JavaScript nie jest językiem obiektowym opartym na klasach. Ale nadal ma sposoby korzystania z programowania obiektowego (OOP).
w tym tutorialu wyjaśnię OOP i pokażę, jak z niego korzystać.
według Wikipedii programowanie oparte na klasach to
styl programowania obiektowego (OOP), w którym dziedziczenie następuje poprzez definiowanie klas obiektów, zamiast dziedziczenia za pośrednictwem samych obiektów
najpopularniejszym modelem OOP jest oparty na klasach.
ale jak już wspomniałem, JavaScript nie jest langauge opartym na klasach-to jest langauge oparty na prototypach.
według dokumentu Mozilli:
język oparty na prototypach ma pojęcie obiektu prototypowego, obiektu używanego jako szablon, z którego można uzyskać początkowe właściwości nowego obiektu.
spójrz na ten kod:
let names = { fname: "Dillion", lname: "Megida"}console.log(names.fname);console.log(names.hasOwnProperty("mname"));// Expected Output// Dillion// false
zmienna obiektu names
ma tylko dwie właściwości – fname
I lname
. Żadnych metod.
skąd więc pochodzi hasOwnProperty
?
pochodzi z prototypu Object
.
spróbuj zalogować zawartość zmiennej do konsoli:
console.log(names);
po rozwinięciu wyników w konsoli otrzymasz następujące informacje:
zwróć uwagę na ostatnią właściwość – __proto__
? Spróbuj go rozwinąć:
zobaczysz zestaw właściwości pod Object
konstruktor. Wszystkie te właściwości pochodzą z globalnego prototypu Object
. Jeśli przyjrzysz się bliżej, zauważysz również nasz ukryty hasOwnProperty
.
innymi słowy, wszystkie obiekty mają dostęp do prototypuObject
. Nie posiadają tych właściwości, ale mają dostęp do właściwości w prototypie.
właściwość __proto__
wskazuje obiekt, który jest używany jako prototyp.
jest to właściwość dla każdego obiektu, który daje mu dostęp do właściwościObject prototype
.
każdy obiekt posiada domyślnie tę właściwość, która odnosi się doObject Protoype
, chyba że ustawiono inaczej (tzn. gdy__proto__
jest skierowany na inny prototyp).
Modyfikowanie właściwości __proto__
Ta właściwość może być zmodyfikowana przez wyraźne stwierdzenie, że powinna odnosić się do innego prototypu. Do tego celu służą następujące metody:
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);
w konsoli masz to, co:
zwróć uwagę na__proto__
właściwość ispeak
metodę?
Object.create
używa argumentu przekazanego do niego, aby stać się prototypem.
nowe słowo kluczowe
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__
właściwość jest skierowana doDogObject
’s prototype. Pamiętaj jednak ,żeDogObject
’s prototype jest obiektem (parą kluczy i wartości), dlatego posiada również__proto__
właściwość, która odnosi się do globalnegoObject
protoype.
technika ta nazywana jest prototypowym łańcuchem.
zauważ, że: podejścienew
robi to samo coObject.create()
, ale tylko ułatwia, ponieważ robi pewne rzeczy automatycznie dla ciebie.
I tak dalej…
każdy obiekt w Javascript ma domyślnie dostęp do prototypuObject
. Jeśli skonfigurowano do używania innego prototypu, powiedzmy prototype2
, wtedy prototype2
będzie miał również dostęp do prototypu obiektu domyślnie, i tak dalej.
kombinacja obiekt + funkcja
prawdopodobnie jesteś zdezorientowany faktem, żeDogObject
jest funkcją (function DogObject(){}
) I ma właściwości dostępne z notacją kropkową. Jest to określane jako kombinacja obiektów funkcyjnych.
gdy funkcje są zadeklarowane, domyślnie są im przypisane wiele właściwości. Pamiętaj, że funkcje są również obiektami w typach danych JavaScript.
teraz, Klasa
JavaScript wprowadziłaclass
słowo kluczowe w ECMAScript 2015. To sprawia, że JavaScript wydaje się językiem OOP. Ale to tylko cukier syntatyczny nad istniejącą techniką prototypowania. Kontynuuje swoje prototypowanie w tle, ale sprawia, że zewnętrzne ciało wygląda jak OOP. Przyjrzymy się teraz, jak to możliwe.
poniższy przykład jest ogólnym zastosowaniemclass
w 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);
jest to wynik w konsoli:
__proto__
odwołuje się doAnimals
prototyp (który z kolei odwołuje się doObject
prototyp).
z tego widać, że konstruktor definiuje główne cechy, podczas gdy wszystko poza konstruktorem (sing()
Idance()
) są dodatkowymi cechami (prototypami).
w tle, używając podejścia ze słowem kluczowym new
, powyższe przekłada się na:
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");
podklasa
jest to funkcja w OOP, gdzie klasa dziedziczy funkcje z klasy nadrzędnej, ale posiada dodatkowe funkcje, których rodzic nie ma.
na przykład, powiedzmy, że chcesz utworzyć klasę kotów. Zamiast tworzyć klasę od zera – podając na nowo nazwę, wiek i właściwości gatunku, dziedziczysz te właściwości z macierzystej klasy zwierząt.
Ta klasa kotów może mieć wtedy dodatkowe właściwości, takie jak kolor wąsów.
zobaczmy, jak podklasy są wykonane zclass
.
tutaj potrzebujemy rodzica, od którego dziedziczy podklasa. Sprawdź następujący kod:
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");
dzięki powyższemu otrzymujemy następujące wyjścia:
console.log(clara.sing());console.log(clara.whiskers());// Expected Output// "Clara can sing"// "I have indigo whiskers"
po zalogowaniu zawartości Clary w konsoli mamy:
zauważysz, że clara
ma __proto__
właściwość, która odwołuje się do konstruktora Cats
I uzyskuje dostęp do whiskers()
metoda. Ta__proto__
właściwość ma również__proto__
właściwość, która odwołuje się do konstruktoraAnimals
, uzyskując w ten sposób dostęp dosing()
Idance()
name
Iage
są właściwościami, które istnieją na każdym obiekcie utworzonym z tego obiektu.
korzystając z metodyObject.create
, powyższe przekłada się na:
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
jest metodą, która przyjmuje dwa argumenty – obiekt (pierwszy argument) i żądany prototyp (drugi argument).
z powyższego,Animals
funkcja zwraca obiekt zanimalConstructor
jako prototyp. FunkcjaCats
zwraca obiekt zcatConstructor
jako prototyp. catConstructor
z kolei otrzymuje prototypanimalConstructor
.
dlatego zwykłe zwierzęta mają dostęp tylko doanimalConstructor
, ale koty mają dostęp docatConstructor
IanimalConstructor
.
zakończenie
JavaScript wykorzystuje swoją prototypową naturę, aby powitać programistów OOP w swoim ekosystemie. Zapewnia również łatwe sposoby tworzenia prototypów i organizowania powiązanych danych.
języki True OOP nie wykonują prototypów w tle – po prostu zwróć na to uwagę.
Wielkie podziękowania dla Will Sentance ’ s course on Frontend Masters-JavaScript: the Hard Parts of Object Oriented JavaScript. Nauczyłem się wszystkiego, co widzisz w tym artykule (plus trochę dodatkowych badań) z jego kursu. Powinieneś to sprawdzić.
możesz do mnie napisać na Twitterze na iamdillion w razie jakichkolwiek pytań lub uwag.
dzięki za przeczytanie:)