OOJS: Objektorienterad JavaSkripthandledning med exempel
⚡ Smart sammanfattning
Objektorienterad JavaSkript modellerar verkliga entiteter som objekt som bär egenskaper och metoder. Den här sidan förklarar objektliteraler, konstruktorfunktioner, prototyper, ES6-klasser, arv och privata fält med körbara exempel som du kan köra och verifiera.

Vad är OOPS Concept i JavaManus?
Många gånger är variabler eller arrayer inte tillräckliga för att simulera verkliga situationer. JavaMed skript kan du skapa objekt som fungerar som verkliga objekt. En student eller ett hem kan vara ett objekt som har många unika egenskaper. Du kan skapa egenskaper och metoder på dina objekt för att göra programmeringen enklare. Om ditt objekt är en student kommer det att ha egenskaper som förnamn, efternamn och id, plus metoder som calculateRank eller changeAddress. Om ditt objekt är ett hem kommer det att ha egenskaper som antal rum, färg och plats, plus metoder som calculateArea eller changeOwner.
Objektorienterad programmering i JavaManuset vilar därför på fyra idéer som du kommer att stöta på på den här sidan: gruppping tillstånd och beteende i ett objekt, återanvända en ritning genom en konstruktor, dela metoder genom prototypen och begränsa direkt åtkomst till interna data. Om du är nybörjare på språket, börja med detta introduktion till JavaScript och sedan återvända hit.
Hur man skapar ett objekt
Du kan skapa ett objekt så här:
var objName = new Object(); objName.property1 = value1; objName.property2 = value2; objName.method1 = function() { // line of code }
ELLER, med den kortare objektbokstavsformen:
var objName = { property1: value1, property2: value2, method1: function() { // lines of code } };
Åtkomstobjektegenskaper och metoder
Du kan komma åt en egenskap för ett objekt med punktnotation, och du kan anropa en metod genom att lägga till parenteser:
objectname.propertyname; // read a property objectname.methodname(); // call a method objectname["propertyname"]; // bracket notation, useful for dynamic keys
Prova själv detta exempel:
<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>
Produktion:
Student Id: 5 Name: John Smith Average Marks: 87.33333333333333
💡 Tips: Exemplet ovan använder dokument.skriv eftersom den körs inuti editorn på den här sidan. I verkliga projekt, föredra console.log för felsökning eller DOM-metoder som textInnehåll, därför att dokument.skriv rensar sidan när den anropas efter att laddningen är klar.
OOPS konstruktör
Att skapa objekt ett i taget är inte så användbart, eftersom man då skulle behöva upprepa samma kod för varje student. Det är här objektkonstruktorn kommer in i bilden. En konstruktor är en vanlig funktion som anropas med ny nyckelord; det definierar en objekttyp som kan återanvändas för varje enskild instans.
Inuti en konstruktor, detta hänvisar till det nya objektet som byggs, så varje instans får sin egen kopia av de värden som skickas in. Relaterade värden som märken lagras ofta i en array så att de kan summeras i ett enda svep.
Prova själv detta exempel:
<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>
Produktion:
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
Slinga genom ett objekts egenskaper
Syntax:
for (variablename in objectname) { // lines of code to be executed }
För/i slinga används vanligtvis för att gå igenom egenskaperna hos ett objekt. Du kan ge objektet vilket namn som helst variabel, men objektnamnet måste matcha ett objekt som redan finns. Variabeln innehåller egenskapen vid varje omgång nyckel som en sträng, så värdet läses med hakparentesnotation som anställd[x].
Prova själv detta exempel:
<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>
Produktion:
Using for/in loops first: John last: Doe department: Accounts
Två punkter är värda att komma ihåg. En for/in-loop besöker också uppräknbara egenskaper som ärvs genom prototypkedjan, så en guard som Object.prototype.hasOwnProperty.call(employee, x) läggs ofta till. För vanliga dataobjekt, Objekt.nycklar(anställd) or Objekt.poster(anställd) är vanligtvis tydligare, eftersom båda bara returnerar objektets egna egenskaper.
Vad är ES6-klassen syntax i JavaManus?
ECMAScript 2015, vanligtvis kallat ES6, lade till klass nyckelord. En klass är syntaktiskt socker över prototypsystemet som konstruktorfunktionen ovan redan använder: ingen ny objektmodell introducerades. Körning typ av student returnerar fortfarande strängen "function" i en klass, och varje metod som skrivs i klassens innehåll installeras på Student.prototype, vilket innebär att alla instanser delar en kopia av den metoden istället för att varje objekt bär sin egen.
Syntaxen tar också bort en del ojämnheter. Klasskroppar körs alltid i strict-läge och anropar en klass utan ny kastar ett TypeError istället för att tyst förorena det globala objektet, och getters, setters och statiska medlemmar har en dedikerad plats att bo på. Resultatet är kortare kod som uttrycker samma avsikt.
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);
Produktion:
Student Id: 15 Name: John Smith Average Marks: 84.67 function true
De två sista raderna bevisar poängen: klassen är fortfarande en funktion, och metoden på instansen är samma funktionsobjekt som lagras på prototypen.
Konstruktorfunktion vs ES6-klass
| Aspect | Konstruktorfunktion | ES6-klass |
|---|---|---|
| Förklaring | funktion Student(…) { } | klass Student { konstruktor(…) { } } |
| Metodplacering | Tilldelad inuti funktionen, så varje instans får sin egen kopia om du inte skriver till Student.prototype | Skrivet i klassens innehåll och placerat automatiskt på prototypen |
| Ringer utan nytt | Går tyst och detta är odefinierat eller det globala objektet | Kasta ett TypeError omedelbart |
| lyft | Funktionsdeklarationer är upphävda och kan användas före definitionen | I den temporala dödzonen tills utvärdering |
| Strikt läge | Följer det omgivande skriptet | Alltid strikt |
| Arv | Manuell: Objekt.skapa plus en Ring till föräldern | sträcker och super |
| Privata data | Stängningar eller en namngivningskonvention som t.ex. _balans | Riktiga privata fält med # |
| Underliggande modell | Prototyper | Prototyper (identiska vid körning) |
Hur man implementerar arv med hjälp av extends och super
Arv låter en specialiserad typ återanvända egenskaperna och metoderna från en mer generell typ. Före ES6 innebar detta att prototypkedjan kopplades manuellt i tre separata steg, och det var lätt att glömma ett av 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);
Produktion:
I am Kevin White true
Ocuco-landskapet sträcker sökordet utför alla tre stegen åt dig, och super ger ett tydligt sätt att nå föräldern. Det finns två olika användningsområden för super:
- super(…) som ett samtal kör den överordnade konstruktorn. Den är bara giltig inuti en härledd konstruktor, och den måste köras innan du rör vid detta, annars utlöses ett ReferenceError.
- super.metod() eftersom en egenskapssökning anropar förälderversionen av en metod som barnet har åsidosatt, vilket är så du utökar beteendet istället för att ersätta det.
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);
Produktion:
I am Hannah Turner, roll number 23 true true true
Den tredje raden är den viktiga. Den bekräftar att sträcker producerade exakt prototypen länkade den manuella versionen som byggdes för hand, så klasser ersatte inte prototypkedjan. De dolde helt enkelt standardtexten. När en egenskap läses från st, motorn tittar på instansen, sedan Student.prototypeoch sedan Person.prototypoch sedan Objekt.prototyp, och stannar vid den första matchningen; den sökvägen är prototypkedjan.
⚠️ Varning: Tilldela aldrig Student.prototype = Person.prototypeDet gör att båda typerna delar ett objekt, så alla metoder du lägger till i det underordnade objektet läggs också till i det överordnade objektet. Objekt.skapa(Person.prototyp), eller helt enkelt använda sträcker.
Hur man uppnår inkapsling med privata klassfält
Inkapsling betyder keeping internt tillstånd utom räckhåll så att det bara kan förändras genom metoder du kontrollerar. I åratal JavaSkriptutvecklare fejkade det med ett inledande understreck, men ett namn som _balans är bara en konvention och vilken kod som helst kan fortfarande skriva över den. Modern JavaSkript erbjuder verklig integritet: ett fält vars namn börjar med # är endast tillgänglig inuti den klasskropp som deklarerar den.
Privata fält medför tre konkreta fördelar:
- De måste deklareras i klasskroppen före användning, vilket dokumenterar typens interna tillstånd på ett ställe.
- De är osynliga för Objektnycklar, JSON.stringify, och for/in, så att internt tillstånd inte läcker in i serialiserad utdata.
- Att vidröra ett privat fält utanför klassen är ett syntaxfel, som upptäcks innan koden ens körs, snarare än en tyst bugg.
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));
Produktion:
John balance: 750
Deposit must be positive
Read via getter: 750
Own keys: owner
JSON: {"owner":"John"}
Balansen syns aldrig i Objektnycklar eller i JSON-strängen, och den negativa insättningen avvisas av metoden istället för att korrumpera fältet. få balans() accessorn exponerar en skrivskyddad vy, vilket är det vanliga sättet att publicera privat tillstånd på ett säkert sätt.
Nu när objekt, prototyper, klasser, arv och inkapsling är begripliga, fortsätt bygga. Öva på grunderna med dessa praktisk JavaExempel på skriptkod, arbeta igenom interaktiva JavaManusövningar, tillämpa klasser på algoritmer som snabbsortering i JavaScript, städa upp utdata med hjälp av JavaFormatering av skriptsträngar, och se hur statisk typing ändrar objektdesign i TypeScript.
