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; }}
User
s konstruktör har en parameter name
, som används för att ställa in det ursprungliga värdet för fältet User
s 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:
- fält på klassinstansen
- fält på klassen själv (aka statisk)
fälten har också 2 nivåer av tillgänglighet:
- Offentlig: fältet är tillgängligt var som helst
- 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 = name
skapar 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ältname
och 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 static
följt av en vanlig metodsyntax:static myStaticMethod() { ... }
.
När du arbetar med statiska metoder finns det 2 enkla regler att komma ihåg:
- en statisk metod kan komma åt statiska fält
- 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?