JavaScript använder prototypiskt arv: varje objekt ärver egenskaper och metoder från dess prototypobjekt.

den traditionella klassen som ritningen för att skapa objekt, som används på språk som Java eller Swift, existerar inte i JavaScript. Det prototypala arvet handlar bara om föremål.

det prototypala arvet kan efterlikna det klassiska klassarvet. För att få de traditionella klasserna till JavaScript introducerar ES2015 standardclass syntax: ett syntaktiskt socker över det prototypa arvet.,

det här inlägget bekantar dig med JavaScript-klasser: så här definierar du en klass, initierar instansen, definierar fält och metoder, förstår de privata och offentliga fälten, förstår de statiska fälten och metoderna.

1. Definition: klass nyckelord

det speciella nyckelordetclass definierar en klass I JavaScript:

koden ovan definierar en klassUser. De lockiga hängslen { } avgränsar klasskroppen. Observera att denna syntax heter klassdeklaration.,

du är inte skyldig att ange klassnamnet. Genom att använda ett klassuttryck kan du tilldela klassen till en variabel:

const UserClass = class { // The body of class};

Du kan enkelt exportera en klass som en del av en ES2015-modul. Här är syntaxen för en standardexport:

export default class User { // The body of class}

och en namngiven export:

export class User { // The body of class}

klassen blir användbar när du skapar en instans av klassen. En instans är ett objekt som innehåller data och beteende som beskrivs av klassen.,

new operatören instansierar klassen i JavaScript:instance = new Class().

Du kan till exempel instansieraUser – klassen mednew operator:

const myUser = new User();

new User() skapar en instans avUser new User() klass.

2. Initiering: konstruktör ()

constructor(param1, param2, ...) är en speciell metod i kroppen av en klass som initierar instansen., Det är den plats där du ställer in de ursprungliga värdena för fälten, eller gör någon form av objektinställning.

i följande exempel anger konstruktören det ursprungliga värdet för fältet name:

class User { constructor(name) { this.name = name; }}

Users konstruktör har en parameter name, som används för att ställa in det ursprungliga värdet för fältet Users konstruktör har en parameter name, som används för att ställa in det ursprungliga värdet för fältet . this.name.

inuti konstruktörenthis värdet motsvarar den nyskapade instansen.,

argumenten som används för att instansera klassen blir parametrarna för konstruktören:

class User { constructor(name) { name; // => 'Jon Snow' this.name = name; }}const user = new User('Jon Snow');

name parametern inuti konstruktören har värdet'Jon Snow'.

om du inte definierar en konstruktör för klassen skapas en standard. Standardkonstruktören är en tom funktion som inte ändrar instansen.

samtidigt kan en JavaScript-klass ha upp till en konstruktör.

3. Fält

Klassfält är variabler som innehåller information., Fält kan fästas på 2 enheter:

  1. fält på klassinstansen
  2. fält på klassen själv (aka statisk)

fälten har också 2 nivåer av tillgänglighet:

  1. Offentlig: fältet är tillgängligt var som helst
  2. privat: fältet är endast tillgängligt inom klassens kropp

3.1 offentliga instansfält

låt oss titta igen på fältet öregående kodavsnitt:

class User { constructor(name) { this.name = name; }}

uttrycket this.name = nameskapar ett instansfält name och tilldelar det ett initialvärde.,

senare kan du komma åtname fält med en egenskapsåtkomst:

const user = new User('Jon Snow');user.name; // => 'Jon Snow'

name är ett offentligt fält eftersom du kan komma åt det utanför klasskroppenUser.

När fälten skapas implicit inuti konstruktören, som i föregående scenario, kan det vara svårt att förstå fältlistan. Du måste dechiffrera dem från konstruktörens kod.

ett bättre tillvägagångssätt är att uttryckligen deklarera klassfälten., Oavsett vad konstruktören gör har instansen alltid samma uppsättning fält.

förslaget om klassfält låter dig definiera fälten inuti klassens kropp. Dessutom kan du ange det ursprungliga värdet direkt:

class SomeClass { field1; field2 = 'Initial value'; // ...}

låt oss ändra klassen User och deklarera ett offentligt fält name:

class User { name; constructor(name) { this.name = name; }}const user = new User('Jon Snow');user.name; // => 'Jon Snow'

name; inne i klassen deklarerar ett offentligt fält name.,

de offentliga fält som deklareras på ett sådant sätt är uttrycksfulla: en snabb titt på fälten deklarationer är tillräckligt för att förstå klassens datastruktur.

dessutom kan klassfältet initieras direkt vid deklaration.

class User { name = 'Unknown'; constructor() { // No initialization }}const user = new User();user.name; // => 'Unknown'

name = 'Unknown'inuti klasskroppen deklarerar ett fältnameoch initierar det med värde'Unknown'.

det finns ingen begränsning för åtkomst eller uppdatering av de offentliga fälten., Du kan läsa och tilldela värden till offentliga fält i konstruktören, metoderna och utanför klassen.

3.2 privata instansfält

inkapsling är ett viktigt koncept som låter dig dölja de interna detaljerna i en klass. Någon som använder en inkapslad klass beror bara på det offentliga gränssnitt som klassen tillhandahåller, och kopplar inte till implementeringsdetaljerna för klassen.

klasser som organiseras med inkapsling i åtanke är lättare att uppdatera när implementeringsdetaljer ändras.,

ett bra sätt att dölja interna data för ett objekt är att använda de privata fälten. Det här är de fält som kan läsas och ändras endast inom klassen de tillhör. Klassens omvärld kan inte ändra privata fält direkt.

de privata fälten är endast tillgängliga inom klassens kropp.

prefixa fältnamnet med specialsymbolen # för att göra det privat, t.ex. #myField., Prefixet# måste behållas varje gång du arbetar med fältet: deklarera det, läsa det eller ändra det.

låt oss se till att fältet#name kan ställas in en gång vid initieringen av instansen:

#name är ett privat fält. Du kan komma åt och ändra #name I kroppen av User. Metoden getName()(mer om metoder i nästa avsnitt) kan komma åt det privata fältet#name.,

men om du försöker komma åt det privata fältet#name utanförUser klasskropp kastas ett syntaxfel:SyntaxError: Private field '#name' must be declared in an enclosing class.

3.3 offentliga statiska fält

Du kan också definiera fält i själva klassen: de statiska fälten. Dessa är till hjälp för att definiera klasskonstanter eller lagra information som är specifik för klassen.

för att skapa statiska fält i en JavaScript-klass, använd det speciella sökordet static följt av fältnamnet: static myStaticField.,

låt oss lägga till ett nytt fält type som anger användartypen: admin eller regular. De statiska fältenTYPE_ADMIN ochTYPE_REGULAR är praktiska konstanter för att skilja användartyperna:

static TYPE_ADMIN ochstatic TYPE_REGULAR definierar statiska variabler i klassenUser. För att komma åt de statiska fälten måste du använda klassen följt av fältnamnet: User.TYPE_ADMIN och User.TYPE_REGULAR.

3.,4 privata statiska fält

Ibland är även de statiska fälten en implementeringsdetalj som du vill dölja. I detta avseende kan du göra statiska fält privata.

för att göra det statiska fältet privat, prefixa fältnamnet med # specialsymbol: static #myPrivateStaticField.

låt oss säga att du vill begränsa antalet instanser av klassenUser., För att dölja detaljerna om instanser gränser, kan du skapa privata statiska fält:

det statiska fältet User.#MAX_INSTANCES anger det maximala antalet tillåtna instanser, medan User.#instances statiskt fält räknar det faktiska antalet instanser.

dessa privata statiska fält är endast tillgängliga inom klassenUser. Ingenting från den yttre världen kan störa begränsningsmekanismen: det är fördelen med inkapsling.

4. Metoder

fälten innehåller data., Men möjligheten att ändra data utförs av speciella funktioner som ingår i klassen: metoderna.

JavaScript-klasserna stöder både instans-och statiska metoder.

4.1 Instansmetoder

Instansmetoder kan komma åt och ändra instansdata. Instansmetoder kan anropa andra instansmetoder, liksom alla statiska metoder.,

låt oss till exempel definiera en metod getName() som returnerar namnet i klassen User:

i en klassmetod, såväl som i konstruktören, är värdet this lika med klassinstansen. Användthis för att komma åt instansdata:this.field, eller ens ringa andra metoder:this.method().,

låt oss lägga till en ny metodnameContains(str) som har en parameter och anropar en annan metod:

nameContains(str) { ... } är en metod förUser klass som accepterar en parameterstr. Mer än så utför den en annan metod för instansen this.getName() för att få användarens namn.

en metod kan också vara privat. För att göra metoden privat prefix sitt namn med #.

låt oss göragetName() metod privat:

#getName() är en privat metod., Inuti metoden nameContains(str) kallar du en privat metod så: this.#getName().

att vara privat,#getName() kan inte anropas utanför klasskroppenUser.

4.2 Getters och setters

getter och setter efterliknar det vanliga fältet, men med mer kontroll över hur fältet nås och ändras.

getter körs vid ett försök att få fältvärdet, medan setter vid ett försök att ställa in ett värde.,

för att se till att egenskapenname för egenskapenUser inte kan vara tom, låt oss slå in det privata fältet#nameValue I en getter och setter:

get name() {...} getter körs när du får tillgång till värdet på fältet:.

4.3 statiska metoder

de statiska metoderna är funktioner som är kopplade direkt till klassen. De har logik relaterad till klassen, snarare än till klassens instans.,

för att skapa en statisk metod använd det speciella sökordet staticföljt av en vanlig metodsyntax:static myStaticMethod() { ... }.

När du arbetar med statiska metoder finns det 2 enkla regler att komma ihåg:

  1. en statisk metod kan komma åt statiska fält
  2. en statisk metod kan inte komma åt instansfält.

låt oss till exempel skapa en statisk metod som upptäcker om en användare med ett visst namn redan har tagits.,

isNameTaken()är en statisk metod som använder det statiska privata fältet User.#takenNames för att söka efter namn som tagits.

5. Arv: utökar

klasserna i JavaScript stöder enstaka arv med hjälp av nyckelordet extends.

i uttrycketclass Child extends Parent { } klassenChild ärver frånParent konstruktören, fälten och metoderna.

låt oss till exempel skapa en ny barnklass ContentWriter som utökar moderklassen User.,

ContentWriter ärver frånUser konstruktören, metodengetName() och fältetname. Dessutom deklarerar klassenContentWriter ett nytt fältposts.

Observera att privata medlemmar i en överordnad klass inte ärvs av underordnad klass.

5.1 överordnad konstruktör: super() i konstruktör ()

om du vill ringa överordnad konstruktör i en underordnad klass måste du användasuper() specialfunktion som finns tillgänglig i barnkonstruktören.,

till exempel, låt oss göra ContentWriter konstruktören ringa den överordnade konstruktören av User, samt initiera fältet inlägg:

super(name) inne i barnklassen ContentWriter utför konstruktören av överordklassen User.

Observera att inuti barnkonstruktören måste du körasuper() innan du använderthis nyckelord. Anropa super() ser till att den överordnade konstruktören initierar instansen.,

class Child extends Parent { constructor(value1, value2) { // Does not work! this.prop2 = value2; super(value1); }}

5.2 överordnad instans: super I metoder

om du vill komma åt den överordnade metoden i en underordnad metod kan du använda den speciella genvägen super.

getName() I barnklassen ContentWriter använder metoden super.getName() direkt från moderklassen User.

den här funktionen kallas method overriding.

Observera att du kan använda super med statiska metoder för att komma åt föräldrarnas statiska metoder.

6., Object type checking: instanceof

object instanceof Class is the operator that determines if object is an instance of Class.

Let’s see instanceof operator in action:

user is an instance of User class, user instanceof User evaluates to true.

The empty object {} is not an instance of User, correspondingly obj instanceof User is false.,

instanceof är polymorf: operatören upptäcker ett barn som en instans av moderklassen.

writerär en instans av barnklassen ContentWriter. Operatören writer instanceof ContentWriter utvärderar till true.

samtidigt ContentWriter är en barnklass av User. Såwriter instanceof User utvärderar tilltrue också.

vad händer om du vill bestämma den exakta klassen av instansen?, Du kan använda egenskapen constructor och jämföra direkt med klassen:

writer.constructor === ContentWriter; // => truewriter.constructor === User; // => false

7. Klasser och prototyper

jag måste säga att klassens syntax i JavaScript gör ett bra jobb att abstrahera från prototypen arv. För att beskriva syntaxenclass har jag inte ens använt termen prototyp.

men klasserna är byggda ovanpå prototypen arv. Varje klass är en funktion och skapar en instans när den anropas som konstruktör.

följande två kodavsnitt är likvärdiga.,

klassversionen:

versionen med prototyp:

klassens syntax är mycket lättare att arbeta om du är bekant med den klassiska arvsmekanismen för Java eller Swift-språk.

ändå, även om du använder klass syntax i JavaScript, rekommenderar jag att du har ett bra grepp om prototypisk arv.

8. Klassfunktioner tillgänglighet

klassfunktionerna som presenteras i det här inlägget är spridda över ES2015 och förslag i steg 3.,

i slutet av 2019 delas klassfunktionerna mellan:

  • offentliga och privata instansfält är en del av Klassfältsförslag
  • privata instansmetoder och accessorer är en del av klassens privata metoder förslag
  • offentliga och privata statiska fält och privata statiska metoder är en del av klassens statiska funktioner förslag
  • resten är en del av ES2015-standarden.

9. Slutsats

JavaScript-klasser initierar instanser med konstruktörer, definierar fält och metoder., Du kan bifoga fält och metoder även på klassen själv med hjälp av nyckelordet static.

Arv uppnås med hjälp avextends nyckelord: Du kan enkelt skapa en barnklass från en förälder. super nyckelord används för att komma åt överordnad klass från en underordnad klass.

för att dra nytta av inkapsling, gör fälten och metoderna privata för att dölja de interna detaljerna i dina klasser. De privata fälten och metoderna måste börja med #.,

klasserna i JavaScript blir allt bekvämare att använda.

vad tycker du om att använda# för att prefix privata egenskaper?