När vi utvecklar något behöver vi ofta våra egna felklasser för att återspegla specifika saker som kan gå fel i våra uppgifter. För fel i nätverksoperationer kan vi behöva HttpError
, för databasoperationer DbError
, för att söka NotFoundError
och så vidare.
våra fel bör stödja grundläggande felegenskaper sommessage
,name
och, helst,stack
. Men de kan också ha andra egenskaper av sina egna, t. ex., HttpError
objekt kan ha enstatusCode
egenskap med ett värde som404
eller403
eller500
.
JavaScript tillåter att användathrow
med något argument, så tekniskt sett behöver våra egna felklasser inte ärva frånError
. Men om vi ärver blir det möjligt att använda obj instanceof Error
för att identifiera felobjekt. Så det är bättre att ärva från det.
När programmet växer bildar våra egna fel naturligtvis en hierarki., Till exempel kan HttpTimeoutError
ärva från HttpError
och så vidare.
utöka fel
som ett exempel, låt oss överväga en funktionreadUser(json)
som bör läsa JSON med användardata.
här är ett exempel på hur ett giltigt json
kan se ut:
let json = `{ "name": "John", "age": 30 }`;
Internt använder viJSON.parse
. Om den tar emot felaktigt json
, kastar den SyntaxError
., Men även om json
är syntaktiskt korrekt betyder det inte att det är en giltig användare, eller hur? Det kan sakna nödvändiga uppgifter. Det kan till exempel inte ha name
och age
egenskaper som är väsentliga för våra användare.
vår funktionreadUser(json)
kommer inte bara läsa JSON, men kontrollera (”validera”) data. Om det inte finns några obligatoriska fält, eller formatet är fel, så är det ett fel. Och det är inte en SyntaxError
, eftersom data är syntaktiskt korrekt, men en annan typ av fel., Vi kallar det ValidationError
och skapar en klass för den. Ett sådant fel bör också innehålla information om det felande fältet.
vårValidationError
klass bör ärva från den inbyggdaError
klass.
den klassen är inbyggd, men här är dess ungefärliga kod så att vi kan förstå vad vi utökar:
låt oss nu ärva ValidationError
från den och prova den i åtgärd:
Observera: i raden (1)
kallar vi den överordnade konstruktören., JavaScript kräver att vi anropar super
I barnkonstruktören, så det är obligatoriskt. Den överordnade konstruktören ställer in egenskapenmessage
.
den överordnade konstruktören ställer också in egenskapenname
till"Error"
, så i raden(2)
återställer vi den till rätt värde.,
låt oss försöka använda den ireadUser(json)
:
try..catch
blocket i koden ovan hanterar både vårValidationError
och den inbyggdaSyntaxError
frånJSON.parse
.
ta en titt på hur vi använderinstanceof
för att kontrollera den specifika feltypen i raden(*)
.,
vi kan också titta på err.name
, så här:
// ...// instead of (err instanceof SyntaxError)} else if (err.name == "SyntaxError") { // (*)// ...
instanceof
versionen är mycket bättre, för i framtiden kommer vi att förlänga ValidationError
instanceof
div>, gör undertyper av det, som PropertyRequiredError
. Ochinstanceof
check fortsätter att fungera för nya ärvklasser. Så det är framtidssäkert.
det är också viktigt att om catch
möter ett okänt fel, omprövar det det i raden (**)
., catch
blocket vet bara hur man hanterar validering och syntaxfel, andra slag (på grund av ett stavfel i koden eller andra okända) bör falla igenom.
ytterligare arv
klassenValidationError
är mycket Generisk. Många saker kan gå fel. Egenskapen kan vara frånvarande eller vara i fel format (som ett strängvärde för age
). Låt oss göra en mer konkret klass PropertyRequiredError
, exakt för frånvarande egenskaper. Den kommer att innehålla ytterligare information om den egendom som saknas.,
den nya klassenPropertyRequiredError
är enkel att använda: vi behöver bara skicka egenskapsnamnet:new PropertyRequiredError(property)
. Den läsbara message
genereras av konstruktören.
Observera attthis.name
IPropertyRequiredError
– konstruktören tilldelas igen manuellt. Det kan bli lite tråkigt – att tilldela this.name = <class name>
I varje Anpassad felklass. Vi kan undvika det genom att göra vår egen ”basic error” – klass som tilldelar this.name = this.constructor.name
. Och sedan ärva alla våra egna fel från det.,
låt oss kalla detMyError
.
här är koden medMyError
och andra anpassade felklasser, förenklad:
nu är anpassade fel mycket kortare, särskiltValidationError
, eftersom vi blev av med linjen"this.name = ..."
I konstruktören.
inslagning undantag
syftet med funktionenreadUser
I koden ovan är ”att läsa användardata”. Det kan förekomma olika typer av fel i processen., Just nu har vi SyntaxError
och ValidationError
, men i framtiden readUser
funktionen kan växa och förmodligen generera andra typer av fel.
koden som anropar readUser
ska hantera dessa fel. Just nu använder den fleraif
s icatch
– blocket, som kontrollerar klassen och hanterar kända fel och omprövar de okända.
schemat är så här:
i koden ovan kan vi se två typer av fel, men det kan finnas mer.,
om funktionenreadUser
genererar flera typer av fel, bör vi Fråga oss själva: vill vi verkligen kontrollera alla feltyper en efter en varje gång?
ofta är svaret ”Nej”: vi vill vara ”en nivå framför allt det”. Vi vill bara veta om det fanns ett ”dataläsningsfel” – varför exakt det hände är ofta irrelevant (felmeddelandet beskriver det). Eller, ännu bättre, vi skulle vilja ha ett sätt att få fel detaljer, men bara om vi behöver.
den teknik som vi beskriver här kallas ”inslagning undantag”.,
- vi gör en ny klass
ReadError
för att representera ett generiskt ”dataläsningsfel”. - funktionen
readUser
kommer att fånga dataläsningsfel som uppstår inuti den, till exempelValidationError
ochSyntaxError
, och generera enReadError
istället. - objektet
ReadError
behåller referensen till det ursprungliga felet i egenskapencause
.,
då måste koden som anroparreadUser
bara kontrolleraReadError
, inte för alla typer av dataläsningsfel. Och om det behöver mer information om ett fel kan det kontrollera dess cause
– egendom.,
här är koden som definierarReadError
och visar dess användning ireadUser
ochtry..catch
:
i koden ovan fungerarreadUser
exakt som beskrivet – fångar syntax och valideringsfel och kastarReadError
fel istället (okända fel återväxt som vanligt).
så kontrollerar den yttre kodeninstanceof ReadError
och det är det. Du behöver inte lista alla möjliga feltyper.,
tillvägagångssättet kallas ”inslagning undantag”, eftersom vi tar” låg nivå ”undantag och” wrap”dem i ReadError
det är mer abstrakt. Det används ofta i objektorienterad programmering.
sammanfattning
- vi kan ärva från
Error
och andra inbyggda felklasser normalt. Vi behöver bara ta hand om egenskapenname
och glöm inte att ringasuper
. - vi kan använda
instanceof
för att söka efter särskilda fel. Det fungerar också med arv., Men ibland har vi ett felobjekt som kommer från ett 3: e parts bibliotek och det finns inget enkelt sätt att få sin klass. Då kanname
– egenskapen användas för sådana kontroller. - inslagning undantag är en utbredd teknik: en funktion hanterar låg nivå undantag och skapar högre nivå fel i stället för olika låg nivå sådana. Undantag på låg nivå blir ibland egenskaper för det objektet som
err.cause
I exemplen ovan, men det är inte strikt nödvändigt.