OOJS: Obiektowo zorientowany JavaSamouczek skryptu z przykładem
⚡ Inteligentne podsumowanie
Zorientowany obiektowo JavaSkrypt modeluje rzeczywiste byty jako obiekty, które zawierają właściwości i metody. Ta strona wyjaśnia literały obiektów, funkcje konstruktorów, prototypy, klasy ES6, dziedziczenie i pola prywatne z przykładami, które można uruchomić i zweryfikować.

W czym jest koncepcja OOPS JavaScenariusz?
W wielu przypadkach zmienne lub tablice nie wystarczą do symulacji rzeczywistych sytuacji. JavaSkrypt pozwala tworzyć obiekty, które zachowują się jak obiekty z życia realnego. Student lub dom mogą być obiektami o wielu unikalnych cechach. Możesz tworzyć właściwości i metody dla swoich obiektów, aby ułatwić programowanie. Jeśli Twoim obiektem jest student, będzie on posiadał właściwości takie jak imię, nazwisko i identyfikator, a także metody takie jak calculatorRank lub changeAddress. Jeśli Twoim obiektem jest dom, będzie posiadał właściwości takie jak liczba pokoi, kolor farby i lokalizacja, a także metody takie jak calculatorArea lub changeOwner.
Programowanie obiektowe w JavaSkrypt opiera się zatem na czterech ideach, które spotkasz na tej stronie: grupaping stan i zachowanie w obiekcie, ponowne wykorzystanie projektu za pomocą konstruktora, współdzielenie metod za pośrednictwem prototypu i ograniczenie bezpośredniego dostępu do danych wewnętrznych. Jeśli dopiero zaczynasz przygodę z językiem, zacznij od tego. wprowadzenie do JavaScenariusz a potem wróć tutaj.
Jak utworzyć obiekt
Możesz stworzyć taki obiekt:
var objName = new Object(); objName.property1 = value1; objName.property2 = value2; objName.method1 = function() { // line of code }
LUB, używając krótszej formy obiektu literałowego:
var objName = { property1: value1, property2: value2, method1: function() { // lines of code } };
Uzyskaj dostęp do właściwości i metod obiektu
Dostęp do właściwości obiektu można uzyskać za pomocą notacji kropkowej, a metodę można wywołać, dodając nawiasy:
objectname.propertyname; // read a property objectname.methodname(); // call a method objectname["propertyname"]; // bracket notation, useful for dynamic keys
Wypróbuj sam ten przykład:
<html>
<head>
<title>Objects!!!</title>
<script type="text/javascript">
var student = new Object();
student.fName = "John";
student.lName = "Smith";
student.id = 5;
student.markE = 76;
student.markM = 99;
student.markS = 87;
student.calculateAverage = function()
{
return (student.markE + student.markM + student.markS)/3;
};
student.displayDetails = function()
{
document.write("Student Id: " + student.id + "<br />");
document.write("Name: " + student.fName + " " + student.lName + "<br />");
var avg = student.calculateAverage();
document.write("Average Marks: " + avg);
};
student.displayDetails();
</script>
</head>
<body>
</body>
</html>
Wyjście:
Student Id: 5 Name: John Smith Average Marks: 87.33333333333333
💡 Wskazówka: Powyższy przykład wykorzystuje dokument.zapisz ponieważ działa w edytorze na tej stronie. W rzeczywistych projektach preferuję konsola.log do debugowania lub metod DOM, takich jak Treść tekstowa, Ponieważ dokument.zapisz czyści stronę, gdy zostanie wywołana po zakończeniu ładowania.
Konstruktor OOPS
Tworzenie obiektów pojedynczo nie jest zbyt przydatne, ponieważ wymagałoby powtarzania tego samego kodu dla każdego ucznia. W tym miejscu pojawia się konstruktor obiektów. Konstruktor to zwykła funkcja wywoływana za pomocą nowych Słowo kluczowe; definiuje typ obiektu, który można ponownie wykorzystać w każdej pojedynczej instancji.
Wewnątrz konstruktora, to odnosi się do nowego obiektu, który jest budowany, więc każda instancja otrzymuje własną kopię przekazanych wartości. Powiązane wartości, takie jak znaczniki, są często przechowywane w szyk tak, aby można je było zsumować za jednym razem.
Wypróbuj sam ten przykład:
<html>
<head>
<script type="text/javascript">
function Student(first, last, id, english, maths, science)
{
this.fName = first;
this.lName = last;
this.id = id;
this.markE = english;
this.markM = maths;
this.markS = science;
this.calculateAverage = function()
{
return (this.markE + this.markM + this.markS)/3;
}
this.displayDetails = function()
{
document.write("Student Id: " + this.id + "<br />");
document.write("Name: " + this.fName + " " + this.lName + "<br />");
var avg = this.calculateAverage();
document.write("Average Marks: " + avg + "<br /><br />");
}
}
var st1 = new Student("John", "Smith", 15, 85, 79, 90);
var st2 = new Student("Hannah", "Turner", 23, 75, 80, 82);
var st3 = new Student("Kevin", "White", 4, 93, 89, 90);
var st4 = new Student("Rose", "Taylor", 11, 55, 63, 45);
st1.displayDetails();
st2.displayDetails();
st3.displayDetails();
st4.displayDetails();
</script>
</head>
<body>
</body>
</html>
Wyjście:
Student Id: 15 Name: John Smith Average Marks: 84.66666666666667 Student Id: 23 Name: Hannah Turner Average Marks: 79 Student Id: 4 Name: Kevin White Average Marks: 90.66666666666667 Student Id: 11 Name: Rose Taylor Average Marks: 54.333333333333336
Pętla przez właściwości obiektu
Składnia:
for (variablename in objectname) { // lines of code to be executed }
Dla/w pętla jest zazwyczaj używany do przeglądania właściwości obiektu. Możesz nadać mu dowolną nazwę. zmienna, ale nazwa obiektu musi pasować do obiektu, który już istnieje. W każdym przejściu zmienna przechowuje właściwość klucz jako ciąg znaków, więc wartość jest odczytywana w notacji nawiasowej, takiej jak pracownik[x].
Wypróbuj sam ten przykład:
<html>
<head>
<script type="text/javascript">
var employee={first:"John", last:"Doe", department:"Accounts"};
var details = "";
document.write("<b>Using for/in loops </b><br />");
for (var x in employee)
{
details = x + ": " + employee[x];
document.write(details + "<br />");
}
</script>
</head>
<body>
</body>
</html>
Wyjście:
Using for/in loops first: John last: Doe department: Accounts
Warto pamiętać o dwóch kwestiach. Pętla for/in również przegląda wyliczalne właściwości dziedziczone w łańcuchu prototypów, więc strażnik, taki jak Obiekt.prototype.hasOwnProperty.call(pracownik, x) jest często dodawany. W przypadku zwykłych obiektów danych, Obiekt.keys(pracownik) or Obiekt.wpisy(pracownik) jest zwykle bardziej przejrzyste, ponieważ oba zwracają tylko właściwości obiektu.
Jaka jest składnia klasy ES6? JavaScenariusz?
ECMAScript 2015, powszechnie nazywany ES6, dodał klasa Słowo kluczowe. Klasa to składniowy lukier dla systemu prototypów, z którego korzysta już powyższa funkcja konstruktora: nie wprowadzono żadnego nowego modelu obiektu. Uruchamianie typ studenta w klasie nadal zwraca ciąg „funkcja”, a każda metoda zapisana w ciele klasy jest instalowana Prototyp studenta, co oznacza, że wszystkie instancje współdzielą jedną kopię tej metody zamiast tego, aby każdy obiekt miał swoją własną kopię.
Składnia eliminuje również pewne niedociągnięcia. Ciała klas zawsze są wykonywane w trybie ścisłym, wywołując klasę bez nowych zgłasza błąd TypeError zamiast po cichu zaśmiecać obiekt globalny, a metody getter, setter i elementy statyczne mają dedykowane miejsce do przechowywania. Rezultatem jest krótszy kod, który wyraża tę samą intencję.
class Student { constructor(first, last, id, english, maths, science) { this.fName = first; this.lName = last; this.id = id; this.marks = [english, maths, science]; } calculateAverage() { const total = this.marks.reduce((sum, m) => sum + m, 0); return total / this.marks.length; } displayDetails() { console.log("Student Id: " + this.id); console.log("Name: " + this.fName + " " + this.lName); console.log("Average Marks: " + this.calculateAverage().toFixed(2)); } } const st1 = new Student("John", "Smith", 15, 85, 79, 90); st1.displayDetails(); console.log(typeof Student); console.log(st1.calculateAverage === Student.prototype.calculateAverage);
Wyjście:
Student Id: 15 Name: John Smith Average Marks: 84.67 function true
Ostatnie dwa wiersze dowodzą, że klasa jest nadal funkcją, a metoda na instancji jest dokładnie tym samym obiektem funkcji, który jest przechowywany w prototypie.
Funkcja konstruktora a klasa ES6
| WYGLĄD | Funkcja konstruktora | Klasa ES6 |
|---|---|---|
| Deklaracja | funkcja Student(…) { } | klasa Student { konstruktor(…) { } } |
| Umieszczenie metody | Przypisane wewnątrz funkcji, więc każda instancja otrzymuje własną kopię, chyba że napiszesz do Prototyp studenta | Napisane w treści klasy i umieszczone automatycznie w prototypie |
| Dzwonienie bez nowego | Działa cicho i to jest niezdefiniowany lub obiekt globalny | Natychmiast zgłasza błąd TypeError |
| Podnoszenie | Deklaracje funkcji są podnoszone i gotowe do użycia przed definicją | W martwej strefie czasowej do czasu oceny |
| Tryb ścisły | Podąża za otaczającym scenariuszem | Zawsze surowy |
| Dziedzictwo | Manual: Obiekt.utwórz plus wezwanie do rodzica | rozciąga się oraz wielki |
| Dane prywatne | Zamknięcia lub konwencja nazewnictwa, taka jak _balansować | Prawdziwe prywatne pola z # |
| Model bazowy | prototypy | Prototypy (identyczne w czasie wykonywania) |
Jak wdrożyć dziedziczenie za pomocą extends i super
Dziedziczenie pozwala typowi specjalistycznemu ponownie wykorzystać właściwości i metody typu bardziej ogólnego. Przed ES6 oznaczało to ręczne łączenie łańcucha prototypów w trzech oddzielnych krokach, a łatwo było o jednym z nich zapomnieć.
function Person(fName, lName) { this.fName = fName; this.lName = lName; } Person.prototype.introduce = function () { return "I am " + this.fName + " " + this.lName; }; function Student(fName, lName, id) { Person.call(this, fName, lName); // 1. borrow the parent constructor this.id = id; } Student.prototype = Object.create(Person.prototype); // 2. link the chain Student.prototype.constructor = Student; // 3. repair constructor var st = new Student("Kevin", "White", 4); console.log(st.introduce()); console.log(st instanceof Person);
Wyjście:
I am Kevin White true
rozciąga się słowo kluczowe wykonuje wszystkie trzy kroki za Ciebie i wielki zapewnia czysty sposób dotarcia do rodzica. Istnieją dwa różne zastosowania wielki:
- super(…) jako wezwanie uruchamia konstruktor nadrzędny. Działa on tylko wewnątrz konstruktora pochodnego i musi zostać uruchomiony przed dotknięciem to, w przeciwnym wypadku zgłaszany jest błąd ReferenceError.
- super.metoda() ponieważ wyszukiwanie właściwości wywołuje wersję nadrzędną metody, którą metoda podrzędna nadpisała, w ten sposób rozszerzasz zachowanie zamiast je zastępować.
class Person { constructor(fName, lName) { this.fName = fName; this.lName = lName; } introduce() { return "I am " + this.fName + " " + this.lName; } } class Student extends Person { constructor(fName, lName, id) { super(fName, lName); // must run before "this" is used this.id = id; } introduce() { return super.introduce() + ", roll number " + this.id; } } const st = new Student("Hannah", "Turner", 23); console.log(st.introduce()); console.log(st instanceof Student, st instanceof Person); console.log(Object.getPrototypeOf(Student.prototype) === Person.prototype);
Wyjście:
I am Hannah Turner, roll number 23 true true true
Trzecia linijka jest ważna. Potwierdza, że rozciąga się Wygenerowano dokładnie taki sam prototypowy link, jak w wersji ręcznej, więc klasy nie zastąpiły łączenia prototypów. Po prostu ukryto szablon. Kiedy właściwość jest odczytywana z stsilnik sprawdza instancję, a następnie Prototyp studenta, następnie Osoba.prototyp, następnie Obiekt.prototypi zatrzymuje się na pierwszym dopasowaniu; ta ścieżka wyszukiwania jest łańcuchem prototypów.
⚠️ Ostrzeżenie: Nigdy nie przypisuj Uczeń.prototyp = Osoba.prototyp. Dzięki temu oba typy współdzielą jeden obiekt, więc każda metoda dodana do obiektu potomnego jest również dodawana do obiektu nadrzędnego. Użyj Obiekt.utwórz(Osoba.prototyp)lub po prostu użyj rozciąga się.
Jak osiągnąć hermetyzację przy użyciu pól klas prywatnych
Enkapsulacja oznacza zachowanieping stan wewnętrzny poza zasięgiem, tak że można go zmienić tylko za pomocą kontrolowanych przez siebie metod. Przez lata JavaTwórcy skryptów fałszowali to za pomocą podkreślenia na początku, ale nazwa taka jak _balansować to tylko konwencja i każdy kod może ją nadpisać. Nowoczesne JavaSkrypt zapewnia prawdziwą prywatność: pole, którego nazwa zaczyna się od # jest dostępny tylko w obrębie ciała klasy, w którym jest deklarowany.
Prywatne boiska przynoszą trzy konkretne korzyści:
- Muszą zostać zadeklarowane w ciele klasy przed użyciem, co dokumentuje wewnętrzny stan typu w jednym miejscu.
- Są dla nich niewidzialne Obiekt.klucze, JSON.stringifyoraz for/in, dzięki czemu stan wewnętrzny nie wycieka do wyjścia szeregowego.
- Próba dostępu do prywatnego pola spoza klasy jest błędem składniowym wychwytywanym jeszcze przed uruchomieniem kodu, a nie ukrytym błędem.
class BankAccount { #balance = 0; constructor(owner, opening) { this.owner = owner; this.#balance = opening; } deposit(amount) { if (amount <= 0) { return "Deposit must be positive"; } this.#balance += amount; return this.owner + " balance: " + this.#balance; } get balance() { return this.#balance; } } const acc = new BankAccount("John", 500); console.log(acc.deposit(250)); console.log(acc.deposit(-40)); console.log("Read via getter: " + acc.balance); console.log("Own keys: " + Object.keys(acc)); console.log("JSON: " + JSON.stringify(acc));
Wyjście:
John balance: 750
Deposit must be positive
Read via getter: 750
Own keys: owner
JSON: {"owner":"John"}
Saldo nigdy się nie pojawia Obiekt.klucze lub w ciągu JSON, a ujemny depozyt jest odrzucany przez metodę zamiast uszkadzać pole. uzyskaj saldo() Akcesor udostępnia widok tylko do odczytu, co jest typowym sposobem bezpiecznego publikowania stanu prywatnego.
Skoro obiekty, prototypy, klasy, dziedziczenie i hermetyzacja mają już sens, kontynuuj tworzenie. Ćwicz podstawy z tymi praktyczny JavaPrzykłady kodu skryptu, przepracować interaktywne JavaĆwiczenia skryptowe, zastosuj klasy do algorytmów takich jak szybkie sortowanie w JavaScenariusz, uporządkuj wyjście za pomocą JavaFormatowanie ciągu skryptui zobacz jak statyczny jestping zmienia projekt obiektu w TypeScript.
