OOJS: Objectgeoriënteerd JavaScripthandleiding met voorbeeld

⚡ Slimme samenvatting

Object georiënteerd JavaScript modelleert entiteiten uit de echte wereld als objecten met eigenschappen en methoden. Deze pagina legt objectliteralen, constructorfuncties, prototypes, ES6-klassen, overerving en private velden uit met uitvoerbare voorbeelden die u kunt uitvoeren en controleren.

  • 🧱 Voorwerpen: Een object bundelt gerelateerde eigenschappen en methoden, zodat één variabele een student, een account of een woning kan modelleren.
  • ???? ️ Constructeurs: Een constructorfunctie met dit Maakt meerdere instanties aan op basis van één herbruikbaar ontwerp.
  • 🔁 Opsomming: De for/in-lus doorloopt elke opsombare eigenschap en print de sleutels en waarden zonder de namen vast te leggen.
  • ???? ES6-klassen: Het sleutelwoord 'class' is slechts syntactische suiker; methoden bevinden zich nog steeds op het gedeelde prototype-object.
  • 🧬 Erfenis: `extends` linkt automatisch prototypes, en `super` roept de constructor van de ouderklasse of een overschreven methode aan.
  • 🔒 inkapseling: Velden met een # ervoor blijven privé en zijn verborgen voor Object.keys en JSON.stringify.
  • ⚙️ Praktijk: Elk voorbeeld op deze pagina toont geverifieerde resultaten, zodat u de resultaten kunt vergelijken terwijl u leert.

Object georiënteerd JavaScriptconcepten (OOJS) met objecten, constructors en klassen

Waar zit OOPS-concept in JavaScript?

Vaak zijn variabelen of arrays niet voldoende om situaties uit het echte leven te simuleren. JavaMet Script kun je objecten maken die zich gedragen als objecten uit de echte wereld. Een student of een huis kan bijvoorbeeld een object zijn met veel unieke eigenschappen. Je kunt eigenschappen en methoden aan je objecten toevoegen om het programmeren te vereenvoudigen. Als je object een student is, heeft het eigenschappen zoals voornaam, achternaam en ID, plus methoden zoals calculateRank of changeAddress. Als je object een huis is, heeft het eigenschappen zoals het aantal kamers, de verfkleur en de locatie, plus methoden zoals calculateArea of ​​changeOwner.

Objectgeoriënteerd programmeren in JavaHet script is daarom gebaseerd op vier ideeën die je op deze pagina zult tegenkomen: grouping De status en het gedrag worden in een object vastgelegd, een blauwdruk wordt hergebruikt via een constructor, methoden worden gedeeld via het prototype en directe toegang tot interne gegevens wordt beperkt. Als je nieuw bent in de taal, begin dan hiermee. inleiding tot JavaScript en kom dan hier terug.

Een object maken

U kunt een object als volgt maken:

var objName = new Object();
objName.property1 = value1;
objName.property2 = value2;
objName.method1 = function()
{
  // line of code
}

OF, met behulp van de kortere objectliteralvorm:

var objName = { property1: value1, property2: value2, method1: function()
{
  // lines of code
} };

Toegang tot objecteigenschappen en -methoden

Je kunt een eigenschap van een object benaderen met behulp van puntnotatie, en je kunt een methode aanroepen door haakjes toe te voegen:

objectname.propertyname;   // read a property
objectname.methodname();   // call a method
objectname["propertyname"]; // bracket notation, useful for dynamic keys

Probeer dit voorbeeld zelf:

<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: Het bovenstaande voorbeeld gebruikt document.write omdat het binnen de editor op deze pagina wordt uitgevoerd. In echte projecten is het beter om... console.log voor debuggen of DOM-methoden zoals tekstInhoudomdat document.write De pagina wordt gewist wanneer deze wordt aangeroepen nadat het laden is voltooid.

OOPS-constructeur

Het één voor één aanmaken van objecten is niet erg handig, omdat je dan dezelfde code voor elke student zou moeten herhalen. Dit is waar de objectconstructor in beeld komt. Een constructor is een gewone functie die wordt aangeroepen met de nieuwe sleutelwoord; het definieert een objecttype dat voor elke afzonderlijke instantie hergebruikt kan worden.

Binnen een constructor, dit verwijst naar het nieuwe object dat wordt opgebouwd, zodat elke instantie een eigen kopie ontvangt van de doorgegeven waarden. Gerelateerde waarden, zoals markeringen, worden vaak opgeslagen in een reeks zodat ze in één keer opgeteld kunnen worden.

Probeer dit voorbeeld zelf:

<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 door de eigenschappen van een object

Syntax:

for (variablename in objectname)
{
  // lines of code to be executed
}

De voor/in lus wordt meestal gebruikt om de eigenschappen van een object te doorlopen. Je kunt elke gewenste naam aan het object geven. variabelemaar de objectnaam moet overeenkomen met een object dat al bestaat. Bij elke iteratie bevat de variabele de eigenschap. sleutel als een tekenreeks, dus de waarde wordt gelezen met haakjesnotatie zoals werknemer[x].

Probeer dit voorbeeld zelf:

<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

Twee punten zijn het onthouden waard. Een for/in-lus doorloopt ook opsombare eigenschappen die via de prototypeketen worden overgeërfd, dus een guard zoals Object.prototype.hasOwnProperty.call(employee, x) wordt vaak toegevoegd. Voor eenvoudige dataobjecten, Object.keys(employee) or Object.entries(employee) is meestal duidelijker, omdat beide alleen de eigen eigenschappen van het object retourneren.

Wat is de ES6-klassensyntaxis in JavaScript?

ECMAScript 2015, beter bekend als ES6, voegde de volgende functionaliteit toe: klasse sleutelwoord. Een klasse is syntactische suiker bovenop het prototypesysteem dat de bovenstaande constructorfunctie al gebruikt: er is geen nieuw objectmodel geïntroduceerd. type student Een klasse retourneert nog steeds de string "functie", en elke methode die in de klassebody is geschreven, wordt geïnstalleerd. Student.prototypeDit betekent dat alle instanties één kopie van die methode delen in plaats van dat elk object zijn eigen kopie heeft.

De syntaxis vereenvoudigt ook een aantal zaken. Klasse-body's worden altijd in strikte modus uitgevoerd, waarbij een klasse wordt aangeroepen zonder nieuwe Het genereert een TypeError in plaats van het globale object stilletjes te vervuilen, en getters, setters en statische leden hebben een eigen plek. Het resultaat is kortere code die dezelfde intentie uitdrukt.

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 laatste twee regels bewijzen het punt: de klasse is nog steeds een functie, en de methode op het instantieobject is precies hetzelfde functieobject dat in het prototype is opgeslagen.

Constructorfunctie versus ES6-klasse

Aspect Constructorfunctie ES6-klasse
Verklaring functie Student(…) { } klasse Student { constructor(…) { } }
Methode plaatsing Toegewezen binnen de functie, dus elk exemplaar krijgt zijn eigen kopie, tenzij je schrijft naar... Student.prototype Geschreven in de klassebody en automatisch op het prototype geplaatst
Bellen zonder nieuwe Werkt geruisloos en dit is niet gedefinieerd of het globale object Gooit direct een TypeError.
Hijsen Functiedeclaraties worden gehoist en zijn bruikbaar vóór de definitie. In de tijdelijke dode zone totdat deze is geëvalueerd.
Strikte modus Volgt het omringende script. Altijd streng
Erfenis Handmatig: Object.create plus Bellen aan de ouder strekt en super
Privégegevens Sluitingen of een naamgevingsconventie zoals _evenwicht Echte privévelden met #
Onderliggend model Prototypes Prototypes (identiek tijdens de uitvoering)

Hoe implementeer je overerving met behulp van `extends` en `super`?

Overerving maakt het mogelijk dat een gespecialiseerd type de eigenschappen en methoden van een algemener type hergebruikt. Vóór ES6 betekende dit dat de prototypeketen handmatig in drie afzonderlijke stappen moest worden opgebouwd, en het was gemakkelijk om er een te vergeten.

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

De strekt Keyword voert alle drie de stappen voor je uit, en super Biedt een eenvoudige manier om de ouder te bereiken. Er zijn twee verschillende toepassingen van. super:

  • super(…) als een oproep Voert de constructor van de ouderklasse uit. Deze is alleen geldig binnen een afgeleide constructor en moet worden uitgevoerd voordat je de constructor aanraakt. ditAnders wordt er een ReferenceError gegenereerd.
  • super.methode() Een eigenschapsopzoeking roept de ouderversie aan van een methode die door het kind is overschreven, en zo breid je het gedrag uit in plaats van het te vervangen.
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

De derde regel is de belangrijkste. Die bevestigt dat strekt produceerde exact de prototype-link, de handmatige versie was met de hand gebouwd, dus klassen vervingen de prototype-keten niet. Ze verborgen simpelweg de standaardcode. Wanneer een eigenschap wordt gelezen vanuit stDe engine bekijkt vervolgens het betreffende geval. Student.prototypedan Persoon.prototypedan Object.prototypeen stopt bij de eerste overeenkomst; dat zoekpad is de prototypeketen.

⚠️ Waarschuwing: Nooit toewijzen Student.prototype = Persoon.prototypeDaardoor delen beide typen één object, dus elke methode die je aan het kind toevoegt, wordt ook aan het ouder toegevoegd. Gebruik Object.create(Person.prototype), of gebruik gewoon strekt.

Hoe bereik je inkapseling met privéklassevelden?

Inkapseling betekent behoudenping Interne status buiten bereik, zodat deze alleen kan worden gewijzigd via methoden die u beheert. Jarenlang. JavaScriptontwikkelaars simuleerden het met een underscore aan het begin, maar een naam zoals _evenwicht Het is slechts een conventie en elke code kan die nog steeds overschrijven. Modern JavaScript biedt echte privacy: een veld waarvan de naam begint met # is alleen toegankelijk binnen de klassebody die deze declareert.

Privévelden bieden drie concrete voordelen:

  • Ze moeten vóór gebruik in de klassebody worden gedeclareerd, waardoor de interne status van het type op één plek wordt vastgelegd.
  • Ze zijn onzichtbaar voor Object.sleutels, JSON.stringify, en for/in, zodat interne status niet doorsijpelt naar de geserialiseerde uitvoer.
  • Het benaderen van een privéveld van buiten de klasse is een syntaxfout die wordt opgemerkt voordat de code wordt uitgevoerd, in tegenstelling tot een stille bug.
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"}

De balans verschijnt nooit in Object.sleutels of in de JSON-string, en de negatieve storting wordt door de methode afgewezen in plaats van dat het veld wordt beschadigd. get balance() De accessor geeft een alleen-lezen weergave weer, wat de gebruikelijke manier is om privé-informatie veilig te publiceren.

Nu je objecten, prototypes, klassen, overerving en inkapseling begrijpt, kun je verder bouwen. Oefen de basisprincipes met deze voorbeelden. praktisch JavaScriptcodevoorbeeldenwerk door interactieve JavaScriptoefeningen, klassen toepassen op algoritmen zoals snelsorteren in JavaScript, de uitvoer opruimen met JavaScriptstringopmaaken kijk hoe statisch typing wijzigt het objectontwerp in TypeScript.

Veelgestelde vragen

Het creëert een leeg object, koppelt het aan het prototype van de constructor, voert de constructor uit met "this" gekoppeld aan dat object, en retourneert het. Als de constructor expliciet een object retourneert, wordt die waarde in plaats daarvan geretourneerd.

Gebruik een statische methode wanneer de logica bij het type hoort en niet bij een individuele instantie, zoals een factory die een object bouwt vanuit JSON of een helper die twee instanties vergelijkt. Statische leden worden aangeroepen op de klasse zelf.

Omdat "dit" wordt bepaald door hoe een methode wordt aangeroepen, niet waar deze is geschreven. Het doorgeven van een methode als callback zorgt ervoor dat de ontvanger verloren gaat. Los dit op door de methode in de constructor te binden of door deze als klasseveld te declareren met een pijlfunctie.

Nee. Het declareren van twee methoden met dezelfde naam behoudt alleen de laatste. Simuleer overbelasting door arguments.length te inspecteren, door standaardparameterwaarden te gebruiken of door een enkel optieobject met benoemde eigenschappen te accepteren.

Ja. AI-codeerassistenten kunnen die refactoring goed aan, omdat de kaartping Het is mechanisch. Controleer altijd het resultaat, aangezien assistenten methoden die aan het prototype buiten de constructor zijn gekoppeld, kunnen missen of een aanroep naar de constructor van de ouder kunnen verbreken.

Ja. De gegenereerde code moet nog steeds worden gelezen, beoordeeld en gedebugd. Kennis van hoe prototypes, "this" en private velden zich gedragen, stelt je in staat om een ​​onjuiste suggestie te herkennen voordat deze in productie wordt genomen.

Vat dit bericht samen met: