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.

  • 🧱 Objekt: Ett objekt buntar samman relaterade egenskaper och metoder så att en variabel kan modellera en student, ett konto eller ett hem.
  • 🏗️ Konstruktörer: En konstruktorfunktion med detta skapar många instanser från en enda återanvändbar ritning.
  • 🔁 Uppräkning: For/in-loopen går igenom alla uppräknningsbara egenskaper och skriver ut nycklar och värden utan att hårdkoda namn.
  • 📦 ES6-klasser: Klassnyckelordet är syntactic sugar; metoder finns fortfarande kvar på det delade prototypobjektet.
  • 🧬 Arv: utökar länkar prototyper automatiskt och superanropar föräldrakonstruktorn eller en overridden-metod.
  • 🔒 inkapsling: Fält med prefixet # förblir privata och dolda från Object.keys och JSON.stringify.
  • ⚙️ Öva: Varje exempel på den här sidan visar verifierad utdata, så att du kan jämföra resultaten allt eftersom du lär dig.

Objektorienterad JavaSkriptkoncept (OOJS) med objekt, konstruktorer och klasser

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.

Vanliga frågor

Den skapar ett tomt objekt, länkar det till konstruktorns prototyp, kör konstruktorn med "this" bunden till det objektet och returnerar det. Om konstruktorn returnerar ett objekt explicit returneras det värdet istället.

Använd en statisk metod när logiken tillhör typen snarare än en enskild instans, till exempel en fabrik som bygger ett objekt från JSON eller en hjälpare som jämför två instanser. Statiska medlemmar anropas på själva klassen.

Eftersom "detta" bestäms av hur en metod anropas, inte var den skrivs. Om en metod skickas som ett återanrop förloras mottagaren. Åtgärda det genom att binda metoden i konstruktorn eller genom att deklarera den som ett klassfält med en pilfunktion.

Nej. Att deklarera två metoder med samma namn behåller endast den sista. Simulera överbelastning genom att inspektera arguments.length, genom att använda standardparametervärden eller genom att acceptera ett enda options-objekt med namngivna egenskaper.

Ja. AI-kodningsassistenter hanterar den omstruktureringen bra eftersom kartanping är mekanisk. Granska alltid resultatet, eftersom assistenter kan missa metoder som är kopplade till prototypen utanför konstruktorn eller släppa ett anrop till den överordnade konstruktorn.

Ja. Genererad kod måste fortfarande läsas, granskas och felsökas. Att veta hur prototyper, "detta" och privata fält beter sig är det som gör att du kan upptäcka ett felaktigt förslag innan det når produktion.

Sammanfatta detta inlägg med: