OOJS: Olio-orientoitunut JavaSkriptiopas esimerkin kanssa
⚡ Älykäs yhteenveto
Kohdennettu JavaSkripti mallintaa reaalimaailman entiteettejä objekteina, joilla on ominaisuuksia ja metodeja. Tämä sivu selittää objektiliteraalit, konstruktorifunktiot, prototyypit, ES6-luokat, periytymisen ja yksityiset kentät suoritettavien ja tarkistettavien esimerkkien avulla.

Mitä OOPS-konsepti sisältää JavaKäsikirjoitus?
Usein muuttujat tai taulukot eivät riitä simuloimaan tosielämän tilanteita. JavaSkriptien avulla voit luoda objekteja, jotka toimivat kuin oikean elämän objektit. Opiskelija tai koti voi olla objekti, jolla on monia ainutlaatuisia ominaisuuksia. Voit luoda objekteille ominaisuuksia ja metodeja ohjelmoinnin helpottamiseksi. Jos objektisi on opiskelija, sillä on ominaisuuksia, kuten etunimi, sukunimi ja tunnus, sekä metodeja, kuten calculateRank tai changeAddress. Jos objektisi on koti, sillä on ominaisuuksia, kuten huoneiden lukumäärä, maalin väri ja sijainti, sekä metodeja, kuten calculateArea tai changeOwner.
Olio-ohjelmointi JavaKäsikirjoitus perustuu siis neljään ideaan, jotka kohtaat tällä sivulla: ryhmäping tilan ja käyttäytymisen lisääminen objektiin, piirustuksen uudelleenkäyttö konstruktorin kautta, metodien jakaminen prototyypin kautta ja sisäisen datan suoran käytön rajoittaminen. Jos olet uusi kielen käyttäjä, aloita tästä johdanto JavaKäsikirjoitus ja palaa sitten tänne.
Kuinka luoda objekti
Voit luoda objektin seuraavasti:
var objName = new Object(); objName.property1 = value1; objName.property2 = value2; objName.method1 = function() { // line of code }
TAI käyttämällä lyhyempää objektin literaalimuotoa:
var objName = { property1: value1, property2: value2, method1: function() { // lines of code } };
Käytä objektin ominaisuuksia ja menetelmiä
Voit käyttää objektin ominaisuutta pistemerkinnällä ja voit kutsua metodia lisäämällä sulkeita:
objectname.propertyname; // read a property objectname.methodname(); // call a method objectname["propertyname"]; // bracket notation, useful for dynamic keys
Kokeile tätä esimerkkiä itse:
<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>
lähtö:
Student Id: 5 Name: John Smith Average Marks: 87.33333333333333
💡 Vinkki: Yllä olevassa esimerkissä käytetään document.write koska se toimii tämän sivun editorin sisällä. Todellisissa projekteissa suositaan konsolin loki virheenkorjaukseen tai DOM-metodeihin, kuten tekstisisältö, Koska document.write tyhjentää sivun, kun sitä kutsutaan latauksen päätyttyä.
OOPS rakentaja
Objektien luominen yksi kerrallaan ei ole kovin hyödyllistä, koska tällöin joutuisit toistamaan saman koodin jokaiselle opiskelijalle. Tässä kohtaa objektikonstruktori tulee kuvaan. Konstruktori on tavallinen funktio, jota kutsutaan uusi avainsana; se määrittää objektityypin, jota voidaan käyttää uudelleen jokaisessa yksittäisessä instanssissa.
Rakentajan sisällä tätä viittaa uuteen rakennettavaan objektiin, joten jokainen instanssi saa oman kopionsa välitetyistä arvoista. Liittyvät arvot, kuten merkit, tallennetaan usein ryhmä jotta ne voidaan laskea yhteen yhdellä kertaa.
Kokeile tätä esimerkkiä itse:
<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>
lähtö:
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
Kierrä objektin ominaisuuksien läpi
Syntaksi:
for (variablename in objectname) { // lines of code to be executed }
For/in silmukka käytetään yleensä objektin ominaisuuksien läpikäymiseen. Voit antaa sille minkä tahansa nimen. muuttuja, mutta objektin nimen on vastattava jo olemassa olevaa objektia. Jokaisella kierroksella muuttujalla on ominaisuus avain merkkijonona, joten arvo luetaan sulkeissa, kuten työntekijä[x].
Kokeile tätä esimerkkiä itse:
<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>
lähtö:
Using for/in loops first: John last: Doe department: Accounts
Kaksi asiaa on syytä muistaa. For/in-silmukka käy myös läpi prototyyppiketjun kautta periytyviä luetteloituja ominaisuuksia, joten suoja, kuten Object.prototype.hasOwnProperty.call(työntekijä, x) lisätään usein. Yksinkertaisille dataobjekteille Object.keys(työntekijä) or Object.entries(työntekijä) on yleensä selkeämpi, koska molemmat palauttavat vain objektin omat ominaisuudet.
Mikä on ES6-luokan syntaksi? JavaKäsikirjoitus?
ECMAScript 2015, jota kutsutaan yleisesti ES6:ksi, lisäsi luokka avainsana. Luokka on syntaktinen sokeri prototyyppijärjestelmän päälle, jota yllä oleva konstruktorifunktio jo käyttää: uutta oliomallia ei otettu käyttöön. Opiskelijatyyppi luokassa palauttaa edelleen merkkijonon ”function”, ja jokainen luokan runkoon kirjoitettu metodi asennetaan Opiskelija.prototyyppi, mikä tarkoittaa, että kaikki instanssit jakavat yhden kopion kyseisestä metodista sen sijaan, että jokainen objekti kantaisi omaa kopiotaan.
Syntaksi poistaa myös joitakin epätasaisuuksia. Luokan rungot suoritetaan aina tiukassa tilassa kutsuen luokkaa ilman uusi heittää TypeError-virheen sen sijaan, että se saastuttaisi hiljaisesti globaalin objektin, ja getter-, setter- ja staattisilla jäsenillä on oma paikkansa. Tuloksena on lyhyempää koodia, joka ilmaisee saman tarkoituksen.
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);
lähtö:
Student Id: 15 Name: John Smith Average Marks: 84.67 function true
Kaksi viimeistä riviä todistavat asian: luokka on edelleen funktio, ja instanssin metodi on täsmälleen sama funktio-objekti, joka on tallennettu prototyyppiin.
Rakentajafunktio vs. ES6-luokka
| Aspect | Rakentajafunktio | ES6-luokka |
|---|---|---|
| Ilmoitus | funktio Opiskelija(…) { } | luokka Opiskelija { konstruktori(…) { } } |
| Menetelmän sijoittelu | Funktion sisällä määritetty, joten jokainen instanssi saa oman kopionsa, ellet kirjoita siihen Opiskelija.prototyyppi | Kirjoitetaan luokan runkoon ja sijoitetaan prototyyppiin automaattisesti |
| Soitto ilman uutta | Toimii äänettömästi ja tätä on määrittelemätön tai globaali objekti | Heittää TypeError-virheen välittömästi |
| hoisting | Funktiomäärittelyt nostetaan ja niitä voidaan käyttää ennen määritelmää | Ajallisessa kuolleessa vyöhykkeessä, kunnes arvioidaan |
| Tiukka tila | Noudattaa ympäröivää käsikirjoitusta | Aina tiukka |
| Perintö | Manuaalinen: Objekti.luo plus soittaa vanhemmalle | ulottuu ja Super |
| Yksityiset tiedot | Sulkemiset tai nimeämiskäytäntö, kuten _saldo | Aidosti yksityiset kentät # |
| Taustalla oleva malli | prototyypit | Prototyypit (identtiset ajonaikana) |
Perinnön toteuttaminen extends- ja super-komennoilla
Perintä antaa erikoistuneen tyypin käyttää uudelleen yleisemmän tyypin ominaisuuksia ja metodeja. Ennen ES6:ta tämä tarkoitti prototyyppiketjun kytkemistä käsin kolmessa erillisessä vaiheessa, ja yksi niistä oli helppo unohtaa.
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);
lähtö:
I am Kevin White true
ulottuu avainsana suorittaa kaikki kolme vaihetta puolestasi, ja Super tarjoaa selkeän tavan tavoittaa vanhemman. Sanalla on kaksi erillistä käyttötarkoitusta. Super:
- super(…) puheluna suorittaa pääkonstruktorin. Se on kelvollinen vain johdetun konstruktorin sisällä, ja se on suoritettava ennen kuin kosketat tätä, muuten heitetään ReferenceError-virhe.
- super.metodi() ominaisuushakuna kutsuu metodin pääversiota, jonka lapsi on korvannut. Tällä tavoin metodin toimintaa laajennetaan sen korvaamisen sijaan.
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);
lähtö:
I am Hannah Turner, roll number 23 true true true
Kolmas rivi on tärkein. Se vahvistaa, että ulottuu tuotti täsmälleen prototyyppilinkin manuaalisesti rakennetun version mukaisesti, joten luokat eivät korvanneet prototyyppien ketjutusta. Ne yksinkertaisesti piilottivat vakiomallin. Kun ominaisuus luetaan st, moottori tarkastelee instanssia ja sitten Opiskelija.prototyyppi, sitten Henkilö.prototyyppi, sitten Objekti.prototyyppi, ja pysähtyy ensimmäiseen osumaan; tämä hakupolku on prototyyppiketju.
⚠️ Varoitus: Älä koskaan määritä Opiskelija.prototyyppi = Henkilö.prototyyppiTämä tarkoittaa, että molemmilla tyypeillä on yksi yhteinen objekti, joten kaikki lapselle lisäämäsi metodit lisätään myös vanhempaan. Käytä Object.create(Henkilö.prototyyppi), tai käytä yksinkertaisesti ulottuu.
Kuinka saavuttaa kapselointi yksityisten luokkakenttien avulla
Kapselointi tarkoittaa säilytystäping sisäinen tila ulottumattomissasi, jotta se voi muuttua vain hallitsemillasi menetelmillä. Vuosien ajan JavaSkriptien kehittäjät väärensivät sen alaviivalla, mutta nimellä, kuten _saldo on vain käytäntö, ja mikä tahansa koodi voi silti korvata sen. Moderni JavaSkripti tarjoaa todellista yksityisyyttä: kenttä, jonka nimi alkaa # on käytettävissä vain sen luokan rungon sisällä, joka sen määrittelee.
Yksityisillä kentillä on kolme konkreettista hyötyä:
- Ne täytyy deklaroida luokan rungossa ennen käyttöä, mikä dokumentoi tyypin sisäisen tilan yhdessä paikassa.
- Ne ovat näkymättömiä Objektiavaimet, JSON.stringify, ja for/in, jotta sisäinen tila ei vuoda sarjamuotoiseen lähtöön.
- Yksityisen kentän koskettaminen luokan ulkopuolelta on syntaksivirhe, joka havaitaan ennen koodin suorittamista, eikä hiljainen virhe.
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));
lähtö:
John balance: 750
Deposit must be positive
Read via getter: 750
Own keys: owner
JSON: {"owner":"John"}
Saldo ei koskaan näy Objektiavaimet tai JSON-merkkijonossa, ja metodi hylkää negatiivisen talletuksen kentän korruptoinnin sijaan. hae saldo() aksessori näyttää vain luku -näkymän, joka on tavanomainen tapa julkaista yksityinen tila turvallisesti.
Nyt kun oliot, prototyypit, luokat, periytyminen ja kapselointi ovat järkeviä, jatka rakentamista. Harjoittele perusteita näillä. käytännön JavaSkriptikoodiesimerkkejä, käydä läpi vuorovaikutteinen JavaKäsikirjoitusharjoituksia, soveltaa luokkia algoritmeihin, kuten pikalajittelu sisään JavaKäsikirjoitus, siisti tuloste käyttämällä JavaSkriptimerkkijonojen muotoilu, ja katso kuinka staattinen typing muuttaa objektin suunnittelua TypeScript.
