OOJS: Objektorienteret JavaScriptvejledning med eksempel
⚡ Smart opsummering
Objektorienteret JavaScript modellerer virkelige enheder som objekter, der bærer egenskaber og metoder. Denne side forklarer objektliteraler, konstruktørfunktioner, prototyper, ES6-klasser, arv og private felter med eksempler, der kan køres og verificeres.

Hvad er OOPS Concept i JavaManuskript?
Mange gange er variabler eller arrays ikke tilstrækkelige til at simulere virkelige situationer. JavaScripts giver dig mulighed for at oprette objekter, der fungerer som virkelige objekter. En studerende eller et hjem kan være et objekt, der har mange unikke egenskaber. Du kan oprette egenskaber og metoder på dine objekter for at gøre programmering nemmere. Hvis dit objekt er en studerende, vil det have egenskaber som fornavn, efternavn og id, plus metoder som calculateRank eller changeAddress. Hvis dit objekt er et hjem, vil det have egenskaber som antal værelser, malingfarve og placering, plus metoder som calculateArea eller changeOwner.
Objektorienteret programmering i JavaManuskriptet hviler derfor på fire ideer, som du vil møde på denne side: gruppeping tilstand og adfærd i et objekt, genbrug af en blueprint gennem en konstruktør, deling af metoder gennem prototypen og begrænsning af direkte adgang til interne data. Hvis du er ny til sproget, så start med dette introduktion til JavaScript og så vende tilbage hertil.
Sådan opretter du et objekt
Du kan oprette et objekt som dette:
var objName = new Object(); objName.property1 = value1; objName.property2 = value2; objName.method1 = function() { // line of code }
ELLER ved at bruge den kortere objektbogstavelige form:
var objName = { property1: value1, property2: value2, method1: function() { // lines of code } };
Adgang til objektegenskaber og -metoder
Du kan tilgå en egenskab for et objekt med punktumnotation, og du kan kalde en metode ved at tilføje parenteser:
objectname.propertyname; // read a property objectname.methodname(); // call a method objectname["propertyname"]; // bracket notation, useful for dynamic keys
Prøv selv dette eksempel:
<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>
Output:
Student Id: 5 Name: John Smith Average Marks: 87.33333333333333
💡 Tip: Eksemplet ovenfor bruger dokument.skrivning fordi det kører inde i editoren på denne side. I virkelige projekter foretrækkes konsol log til fejlfinding eller DOM-metoder som f.eks. tekstindhold, Fordi dokument.skrivning sletter siden, når den kaldes efter indlæsningen er færdig.
OOPS konstruktør
Det er ikke så nyttigt at oprette objekter ét ad gangen, fordi man så skal gentage den samme kode for hver elev. Det er her, objektkonstruktøren kommer ind i billedet. En konstruktør er en almindelig funktion, der kaldes med ny nøgleord; det definerer en objekttype, der kan genbruges for hver enkelt instans.
Inde i en konstruktør, denne refererer til det nye objekt, der bygges, så hver instans modtager sin egen kopi af de værdier, der sendes ind. Relaterede værdier, såsom mærker, gemmes ofte i en matrix så de kan tælles i én omgang.
Prøv selv dette eksempel:
<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>
Output:
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
Loop gennem et objekts egenskaber
Syntaks:
for (variablename in objectname) { // lines of code to be executed }
For/i loop bruges normalt til at gennemgå et objekts egenskaber. Du kan give det et hvilket som helst navn variabel, men objektnavnet skal matche et objekt, der allerede findes. Ved hver gennemgang holder variablen egenskaben nøgle som en streng, så værdien læses med parentesnotation, f.eks. medarbejder[x].
Prøv selv dette eksempel:
<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>
Output:
Using for/in loops first: John last: Doe department: Accounts
To punkter er værd at huske på. En for/in-løkke besøger også optællelige egenskaber, der er nedarvet gennem prototypekæden, så en vagt som f.eks. Objekt.prototype.harEgenEgenskab.kald(medarbejder, x) tilføjes ofte. For almindelige dataobjekter, Objekt.nøgler(medarbejder) or Objekt.poster(medarbejder) er normalt tydeligere, fordi begge kun returnerer objektets egne egenskaber.
Hvad er ES6-klassen syntaks i JavaManuskript?
ECMAScript 2015, almindeligvis kaldet ES6, tilføjede klasse nøgleord. En klasse er syntaktisk sukker over det prototypesystem, som konstruktørfunktionen ovenfor allerede bruger: ingen ny objektmodel blev introduceret. Kører type af studerende returnerer stadig strengen "function" i en klasse, og alle metoder, der er skrevet i klassens brødtekst, installeres på Student.prototype, hvilket betyder, at alle instanser deler én kopi af den metode i stedet for at hvert objekt bærer sin egen.
Syntaksen fjerner også nogle ujævnheder. Klassekroppe udføres altid i strict mode og kalder en klasse uden ny kaster en TypeError i stedet for lydløst at forurene det globale objekt, og gettere, settere og statiske medlemmer har et dedikeret sted at bo. Resultatet er kortere kode, der udtrykker den samme intention.
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);
Output:
Student Id: 15 Name: John Smith Average Marks: 84.67 function true
De sidste to linjer beviser pointen: klassen er stadig en funktion, og metoden på instansen er det samme funktionsobjekt, der er gemt på prototypen.
Konstruktørfunktion vs. ES6-klasse
| Aspect | Konstruktørfunktion | ES6-klasse |
|---|---|---|
| Erklæring | funktion Studerende(…) { } | klasse Studerende { konstruktør(…) { } } |
| Metodeplacering | Tildelt inde i funktionen, så hver instans får sin egen kopi, medmindre du skriver til Student.prototype | Skrevet i klassens brødtekst og placeret automatisk på prototypen |
| Opkald uden nyt | Kører lydløst og denne er udefineret eller det globale objekt | Kaster en TypeError med det samme |
| hejsning | Funktionsdeklarationer er hævet og kan bruges før definitionen | I den tidsmæssige dødzone indtil evaluering |
| Streng tilstand | Følger det omgivende skrift | Altid streng |
| Arv | Manual: Objekt.opret plus en ringe til forælderen | udvider og super |
| Private data | Lukninger eller en navngivningskonvention som f.eks. _balance | Ægte private felter med # |
| Underliggende model | prototyper | Prototyper (identiske under kørsel) |
Sådan implementerer du arv ved hjælp af extends og super
Arv tillader en specialiseret type at genbruge egenskaberne og metoderne fra en mere generel type. Før ES6 betød dette at forbinde prototypekæden manuelt i tre separate trin, og det var let at glemme et af dem.
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);
Output:
I am Kevin White true
udvider søgeordet udfører alle tre trin for dig, og super giver en nem måde at nå forælderen på. Der er to forskellige anvendelser af super:
- super(…) som et opkald kører den overordnede konstruktør. Den er kun gyldig i en afledt konstruktør, og den skal køre, før du berører denne, ellers udløses en ReferenceError.
- super.metode() da et egenskabsopslag kalder den overordnede version af en metode, som den underordnede har tilsidesat, hvilket er sådan du udvider adfærd i stedet for at erstatte den.
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);
Output:
I am Hannah Turner, roll number 23 true true true
Den tredje linje er den vigtige. Den bekræfter det. udvider producerede præcis prototypen, der linkede til den manuelle version, der blev bygget i hånden, så klasser erstattede ikke prototypekæder. De skjulte blot standardteksten. Når en egenskab læses fra st, motoren kigger på instansen, og derefter Student.prototype, derefter Person.prototype, derefter Objekt.prototype, og stopper ved det første match; den søgesti er prototypekæden.
⚠️ Advarsel: Tildel aldrig Student.prototype = Person.prototypeDet gør, at begge typer deler ét objekt, så enhver metode, du tilføjer til det underordnede objekt, tilføjes også til det overordnede objekt. Objekt.opret(Person.prototype), eller blot bruge udvider.
Sådan opnår du indkapsling med private klassefelter
Indkapsling betyder keeping indre tilstand uden for rækkevidde, så den kun kan ændres gennem metoder, du kontrollerer. I årevis JavaScriptudviklere forfalskede det med et indledende understregningstegn, men et navn som f.eks. _balance er kun en konvention, og enhver kode kan stadig overskrive den. Moderne JavaScript tilbyder ægte privatliv: et felt, hvis navn begynder med # er kun tilgængelig inde i den klassekropp, der deklarerer den.
Private marker medfører tre konkrete fordele:
- De skal deklareres i klassens brødtekst før brug, hvilket dokumenterer typens interne tilstand ét sted.
- De er usynlige for Objektnøgler, JSON.stringify, og for/in, så den interne tilstand ikke lækker ind i serialiseret output.
- At berøre et privat felt uden for klassen er en syntaksfejl, der opdages før koden overhovedet kører, snarere end en stille fejl.
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));
Output:
John balance: 750
Deposit must be positive
Read via getter: 750
Own keys: owner
JSON: {"owner":"John"}
Balancen vises aldrig i Objektnøgler eller i JSON-strengen, og den negative indbetaling afvises af metoden i stedet for at beskadige feltet. få balance() accessor eksponerer en skrivebeskyttet visning, hvilket er den sædvanlige måde at publicere privat tilstand sikkert på.
Nu hvor objekter, prototyper, klasser, arv og indkapsling giver mening, så fortsæt med at bygge. Øv dig i det grundlæggende med disse praktisk JavaEksempler på scriptkode, arbejde igennem interaktiv JavaScriptøvelser, anvende klasser på algoritmer såsom hurtigsortering i JavaScript, rydd op i outputtet ved hjælp af JavaFormatering af scriptstrenge, og se hvor statisk typing ændrer objektdesign i TypeScript.
