7 tips om ongedefinieerd in JavaScript te verwerken
De meeste moderne talen zoals Ruby, Python of Java hebben een enkele nulwaarde (nil
of null
), wat een redelijke benadering lijkt.
Maar JavaScript is anders.
null
, maar ook undefined
, vertegenwoordigen in JavaScript lege waarden. Dus wat is het exacte verschil tussen hen?
Het korte antwoord is dat JavaScript-interpreter undefined
retourneert bij het openen van een variabele of objecteigenschap die nog niet is geïnitialiseerd. Bijvoorbeeld:
Aan de andere kant staat null
voor een ontbrekend object referentie. JavaScript initialiseert geen variabelen of objecteigenschappen met null
.
Sommige native methoden zoals String.prototype.match()
kunnen null
retourneren om een ontbrekend object aan te duiden. Bekijk het voorbeeld:
Omdat JavaScript tolerant is, hebben ontwikkelaars de verleiding om toegang te krijgen tot niet-geïnitialiseerde waarden. Ik maak me ook schuldig aan zulke slechte praktijken.
Vaak genereren dergelijke risicovolle acties undefined
gerelateerde fouten:
-
TypeError: "undefined" is not a function
-
TypeError: Cannot read property "<prop-name>" of undefined
- en soortgelijke typefouten.
JavaScript-ontwikkelaar kan de ironie van deze grap begrijpen :
Om dergelijke fouten te verminderen, moet u de gevallen begrijpen waarin undefined
wordt gegenereerd. Laten we eens kijken naar undefined
en het effect ervan op codeveiligheid.
1. Wat is niet gedefinieerd
JavaScript heeft 6 primitieve typen:
En een gescheiden objecttype: {name: "Dmitri"}
, .
Van 6 primitieve types undefined
is een speciale waarde met zijn eigen type Undefined. Volgens ECMAScript-specificatie:
Ongedefinieerde waarde primitieve waarde wordt gebruikt wanneer een variabele geen waarde is toegewezen.
De standaard definieert duidelijk dat u undefined
ontvangt bij toegang tot niet-geïnitialiseerde variabelen, niet-bestaande objecteigenschappen, niet-bestaande array-elementen, en dergelijke.
Een paar voorbeelden:
Het bovenstaande voorbeeld laat zien dat toegang krijgen tot:
- een niet-geïnitialiseerde variabele
number
- een niet-bestaande objecteigenschap
movie.year
- of een niet-bestaand array-element
movies
worden geëvalueerd als undefined
.
De ECMAScript-specificatie definieert het type undefined
waarde:
Ongedefinieerd type is een type waarvan de enige waarde de
undefined
-waarde is.
In die zin typeof
operator geeft "undefined"
tekenreeks terug voor een undefined
waarde:
Natuurlijk werkt typeof
goed om te verifiëren of een variabele een undefined
-waarde bevat:
2. Scenarios die ongedefinieerde
2.1 Niet-geïnitialiseerde variabele
Een gedeclareerde variabele maar nog niet toegewezen met een waarde (niet-geïnitialiseerd) is standaard
undefined
.
Eenvoudig en duidelijk:
myVariable
is gedeclareerd en nog niet toegewezen met een waarde. Toegang tot de variabele levert undefined
op.
Een efficiënte benadering om de problemen van niet-geïnitialiseerde variabelen op te lossen, is waar mogelijk een beginwaarde toe te kennen. Hoe minder de variabele in een niet-geïnitialiseerde staat bestaat, hoe beter.
Idealiter zou u direct een waarde toekennen na declaratie const myVariable = "Initial value"
. Maar dat is niet altijd mogelijk.
Tip 1: geef de voorkeur aan const
, gebruik anders let
, maar zeg gedag tegen var
Naar mijn mening is een van de beste eigenschappen van ECMAScript 2015 de nieuwe manier om variabelen te declareren met const
en let
. Het is een grote stap voorwaarts.
const
en let
hebben een blokbereik (in tegenstelling tot het oudere functiebereik var
) en bestaan in een tijdelijke dode zone tot de aangiftelijn.
Ik raad const
variabele aan als de waarde ervan niet zal veranderen. Het creëert een onveranderlijke binding.
Een van de leuke eigenschappen van const
is dat je een beginwaarde moet toewijzen aan de variabele const myVariable = "initial"
. De variabele is niet blootgesteld aan de niet-geïnitialiseerde status en toegang tot undefined
is onmogelijk.
Laten we eens kijken naar de functie die verifieert of een woord een palindroom is:
length
en half
variabelen krijgen één keer een waarde toegewezen. Het lijkt redelijk om ze te declareren als const
aangezien deze variabelen niet zullen veranderen.
Gebruik let
declaratie voor variabelen waarvan de waarde kan veranderen. Wijs waar mogelijk meteen een beginwaarde toe, bijv. let index = 0
.
Hoe zit het met de oude school var
? Mijn suggestie is om het niet meer te gebruiken.
var
aangifteprobleem is de variabele hijsen binnen het functiebereik. Je kunt een var
variabele ergens aan het einde van het functiebereik declareren, maar je hebt er nog steeds toegang toe vóór de declaratie: en je krijgt een undefined
.
myVariable
is toegankelijk en bevat undefined
zelfs vóór de aangiftelijn: var myVariable = "Initial value"
.
Een const
of let
variabele kan daarentegen niet worden benaderd vóór de declaratieregel – de variabele bevindt zich in een tijdelijke dode zone vóór de aangifte. En dat is fijn, want je hebt minder kans om toegang te krijgen tot een undefined
.
Het bovenstaande voorbeeld bijgewerkt met let
(in plaats van var
) genereert een ReferenceError
omdat de variabele in de tijdelijke dode zone niet toegankelijk is.
Door het gebruik van const
voor onveranderlijke bindingen of let
aan te moedigen, wordt een praktijk gegarandeerd die het uiterlijk van niet-geïnitialiseerde variabele.
Tip 2: cohesie vergroten
Cohesie kenmerkt de mate waarin de elementen van een module (namespace, class, methode, codeblok) bij elkaar horen. De cohesie kan hoog of laag zijn.
Een module met hoge cohesie heeft de voorkeur omdat de elementen van zon module zich uitsluitend op één taak richten. Het maakt de module:
- Gericht en begrijpelijk: gemakkelijker te begrijpen wat de module doet
- Onderhoudbaar en gemakkelijker te refactoren: de wijziging in de module heeft invloed op minder modules
- Herbruikbaar: door gefocust te zijn op een enkele taak, is het gemakkelijker om de module opnieuw te gebruiken
- Testbaar: je zou gemakkelijker een module testen die gericht is op een enkele taak
Hoge cohesie vergezeld van losse koppeling is het kenmerk van een goed ontworpen systeem.
Een codeblok kan worden beschouwd als een kleine module. Om te profiteren van de voordelen van een hoge cohesie, houdt u de variabelen zo dicht mogelijk bij het codeblok waarin ze worden gebruikt.
Als een variabele bijvoorbeeld alleen bestaat om de logica van het blokbereik te vormen, declareer dan en maak de variabele alleen levend binnen dat blok (met const
of let
declaraties). Stel deze variabele niet bloot aan de scope van het buitenste blok, aangezien het buitenste blok niet om deze variabele zou moeten geven.
Een klassiek voorbeeld van de onnodig verlengde levensduur van variabelen is het gebruik van for
cyclus binnen een functie:
index
, item
en length
variabelen worden gedeclareerd aan het begin van de body van de functie. Ze worden echter pas tegen het einde gebruikt. Wat is het probleem met deze benadering?
Tussen de declaratie bovenaan en het gebruik in de for
instructie de variabelen index
, item
zijn niet geïnitialiseerd en blootgesteld aan undefined
. Ze hebben een onredelijk lange levenscyclus in de gehele functieomvang.
Een betere benadering is om deze variabelen zo dicht mogelijk bij hun gebruiksplaats te verplaatsen:
index
en item
variabelen bestaan alleen in het blokbereik van de for
-instructie. Ze hebben geen betekenis buiten for
.
length
variabele wordt ook dicht bij de bron van zijn gebruik gedeclareerd.
Waarom is de gewijzigde versie beter dan de oorspronkelijke? Laten we eens kijken:
- De variabelen worden niet blootgesteld aan een niet-geïnitialiseerde status, dus u loopt geen risico om
undefined
- Verplaatsen van de variabelen die zo dicht mogelijk bij hun gebruiksplaats liggen, verhoogt de leesbaarheid van de code
- Sterk samenhangende stukjes code zijn gemakkelijker te refactoren en te extraheren in afzonderlijke functies, indien nodig
2.2 Toegang een niet-bestaande eigenschap
Bij het openen van een niet-bestaande objecteigenschap, retourneert JavaScript
undefined
.
Laten we dat in een voorbeeld demonstreren:
favoriteMovie
is een object met een enkele eigenschap title
. Toegang tot een niet-bestaande eigenschap actors
met behulp van een eigenschap accessor favoriteMovie.actors
resulteert in undefined
.
Toegang krijgen tot een niet-bestaande eigenschap geeft geen foutmelding. Het probleem treedt op wanneer wordt geprobeerd gegevens op te halen van de niet-bestaande eigenschap, wat de meest voorkomende undefined
-trap is, weergegeven in de bekende foutmelding TypeError: Cannot read property <prop> of undefined
.
Laten we het vorige codefragment enigszins aanpassen om een TypeError
worp te illustreren:
favoriteMovie
heeft niet de eigenschap actors
, dus favoriteMovie.actors
evalueert naar undefined
.
Als gevolg hiervan genereert toegang tot het eerste item van een undefined
-waarde met behulp van de uitdrukking favoriteMovie.actors
een TypeError
.
Het tolerante karakter van JavaScript dat toegang geeft tot niet-bestaande eigendommen is een bron van non-determinisme: de eigenschap kan al dan niet ingesteld zijn. De goede manier om dit probleem te omzeilen, is door ervoor te zorgen dat het object altijd de eigenschappen heeft gedefinieerd die het bevat.
Helaas heb je vaak geen controle over de objecten. Dergelijke objecten kunnen in verschillende scenarios verschillende eigenschappen hebben. Al deze scenarios moet je dus handmatig afhandelen.
Laten we een functie append(array, toAppend)
implementeren die aan het begin en / of aan het einde van een reeks nieuwe elementen toevoegt. toAppend
parameter accepteert een object met eigenschappen:
-
first
: element ingevoegd aan het begin vanarray
-
last
: element ingevoegd aan het einde vanarray
.
De functie retourneert een nieuwe array-instantie, zonder de originele array te wijzigen.
De eerste versie van append()
, een beetje naïef, kan er als volgt uitzien:
Omdat toAppend
object kan first
of last
eigenschappen weglaten, het is verplicht om te verifiëren of deze eigenschappen bestaan in toAppend
.
Een eigenschap accessor evalueert naar undefined
als de eigenschap niet bestaat. De eerste verleiding om te controleren of de eigenschappen first
of last
aanwezig zijn, is door ze te verifiëren met undefined
. Dit wordt uitgevoerd in conditionals if(toAppend.first){}
en if(toAppend.last){}
…
Niet zo snel. Deze benadering heeft een nadeel. undefined
, evenals false
, null
, 0
, NaN
en ""
zijn onjuiste waarden.
In de huidige implementatie van append()
, staat de functie het invoegen van valse elementen niet toe:
De volgende tips leggen uit hoe u het bestaan van het onroerend goed correct kunt controleren.
Tip 3: Controleer het bestaan van het onroerend goed
Gelukkig biedt JavaScript een aantal manieren om te bepalen of het object een specifieke eigenschap heeft:
-
obj.prop !== undefined
: vergelijk metundefined
direct -
typeof obj.prop !== "undefined"
: verifieer het waardetype van de eigenschap -
obj.hasOwnProperty("prop")
: controleer of de object heeft een eigen eigenschap -
"prop" in obj
: verifieer of het object een eigen of overgenomen eigenschap heeft
Mijn aanbeveling is om gebruik de operator in
. Het heeft een korte en zoete syntaxis. in
aanwezigheid van de operator suggereert een duidelijke bedoeling om te controleren of een object een specifieke eigenschap heeft, zonder toegang tot de werkelijke eigenschapswaarde.
obj.hasOwnProperty("prop")
is ook een mooie oplossing. Het is iets langer dan de operator in
en verifieert alleen in de eigen eigenschappen van het object.
Laten we de append(array, toAppend)
functie verbeteren met de in
operator:
"first" in toAppend
(en "last" in toAppend
) is true
of de bijbehorende eigenschap bestaat, false
anders.
in
operator lost het probleem op met het invoegen van valse elementen 0
en false
. Als u deze elementen nu aan het begin en het einde van toevoegt, krijgt u het verwachte resultaat
.
Tip 4: Vernietigen om toegang te krijgen tot objecteigenschappen
Bij het benaderen van een objecteigenschap is het soms nodig om een standaardwaarde in te stellen als de eigenschap niet bestaat.
U kunt in
gebruiken in combinatie met een ternaire operator om dat te bereiken:
Ternaire operator-syntaxis wordt ontmoedigend wanneer het aantal te controleren eigenschappen toeneemt. Voor elke eigenschap moet je een nieuwe coderegel maken om de standaardinstellingen af te handelen, waardoor een lelijke muur van op elkaar lijkende ternaire operatoren toeneemt.
Om een elegantere benadering te gebruiken, laten we kennis maken met een geweldige ES2015-functie genaamd objectvernietiging.
Objectdestructurering maakt inline extractie van objecteigenschapwaarden rechtstreeks in variabelen mogelijk en stelt een standaardwaarde in als de eigenschap niet bestaat. Een handige syntaxis om te voorkomen dat u rechtstreeks met undefined
omgaat.
Inderdaad, de extractie van eigenschappen is nu nauwkeurig:
Laten we, om dingen in actie te zien, een handige functie definiëren die een string tussen aanhalingstekens plaatst.
quote(subject, config)
accepteert het eerste argument als de string die moet worden ingepakt. Het tweede argument config
is een object met de eigenschappen:
Door de voordelen van de objectvernietiging toe te passen, implementeren we quote()
:
const { char = """, skipIfQuoted = true } = config
door toewijzing op één regel te vernietigen, worden de eigenschappen char
en skipIfQuoted
van config
-object.
Als sommige eigenschappen ontbreken in het config
-object, stelt de vernietigingstoewijzing de standaardwaarden in : """
voor char
en false
voor skipIfQuoted
.
Gelukkig is de functie nog voor verbetering vatbaar.
Laten we de vernietigingsopdracht naar de parameter sectie verplaatsen. En stel een standaardwaarde in (een leeg object { }
) voor de parameter config
, om het tweede argument over te slaan als de standaardinstellingen voldoende zijn.
De vernietigende toewijzing vervangt de config
parameter in de handtekening van de functie. Dat vind ik leuk: quote()
wordt een regel korter.
= {}
aan de rechterkant van de vernietigingstoewijzing zorgt ervoor dat een leeg object wordt gebruikt als het tweede argument helemaal niet is opgegeven quote("Sunny day")
.
Objectvernietiging is een krachtige functie die de extractie van eigenschappen uit objecten efficiënt afhandelt. Ik hou van de mogelijkheid om een standaardwaarde op te geven die moet worden geretourneerd wanneer de geopende eigenschap niet bestaat. Als resultaat vermijdt u undefined
en het gedoe eromheen.
Tip 5: vul het object met standaardeigenschappen
Als het niet nodig is om voor elke eigenschap variabelen aan te maken, zoals bij de vernietigende toewijzing, kan het object dat enkele eigenschappen mist, worden gevuld met standaardwaarden.
De ES2015 Object.assign(target, source1, source2, ...)
kopieert de waarden van alle opsombare eigen eigenschappen van een of meer bronobjecten naar het doelobject. De functie retourneert het doelobject.
U moet bijvoorbeeld toegang hebben tot de eigenschappen van het unsafeOptions
-object dat niet altijd de volledige set eigenschappen bevat.
Om undefined
te vermijden bij het openen van een niet-bestaande eigenschap van unsafeOptions
, laten we enkele aanpassingen maken:
- Definieer een object
defaults
dat de standaard eigenschapswaarden bevat - Roep
Object.assign({ }, defaults, unsafeOptions)
aan om te bouwen een nieuw objectoptions
. Het nieuwe object ontvangt alle eigenschappen vanunsafeOptions
, maar de ontbrekende zijn afkomstig vandefaults
.
unsafeOptions
bevat alleen fontSize
eigenschap. defaults
object definieert de standaardwaarden voor eigenschappen fontSize
en color
.
Object.assign()
neemt het eerste argument als doelobject {}
. Het doelobject ontvangt de waarde van de eigenschap fontSize
van unsafeOptions
bronobject. En de waarde van color
eigenschap van defaults
bronobject, omdat unsafeOptions
geen color
.
De volgorde waarin de bronobjecten worden opgesomd, is van belang: latere bronobjecteigenschappen overschrijven eerdere.
U hebt nu veilig toegang tot alle eigenschappen van options
-object, inclusief options.color
die niet beschikbaar was in unsafeOptions
aanvankelijk.
Gelukkig bestaat er een eenvoudiger alternatief om het object met standaardeigenschappen te vullen.Ik raad aan om de spread-eigenschappen te gebruiken in objectinitializers.
Gebruik in plaats van Object.assign()
aanroep de syntaxis van objectspreiding om alle eigen en opsombare eigenschappen van bronobjecten naar het doelobject te kopiëren:
De objectinitializer verspreidt eigenschappen van defaults
en unsafeOptions
bronobjecten. De volgorde waarin de bronobjecten worden opgegeven, is belangrijk: latere eigenschappen van bronobjecten overschrijven eerdere.
Het vullen van een onvolledig object met standaard eigenschapswaarden is een efficiënte strategie om uw code veilig en duurzaam te maken. Ongeacht de situatie bevat het object altijd de volledige set eigenschappen: en undefined
kan niet worden gegenereerd.
Bonustip: nullish coalescing
De operator nullish coalescing evalueert naar een standaardwaarde wanneer de operand undefined
of :
Nullish coalescing operator is handig om toegang te krijgen tot een objecteigenschap met een standaardwaarde wanneer deze eigenschap is undefined
of null
:
styles
object heeft niet de eigenschap color
, dus styles.color
eigenschap accessor is undefined
. styles.color ?? "black"
evalueert naar de standaardwaarde "black"
.
styles.fontSize
is 18
, dus de nullish coalescing-operator evalueert naar de eigenschapswaarde 18
.
2.3 Functieparameters
De functieparameters zijn impliciet standaard
undefined
.
Gewoonlijk moet een functie gedefinieerd met een specifiek aantal parameters worden aangeroepen met hetzelfde aantal argumenten. Dat is wanneer de parameters de waarden krijgen die u verwacht:
Wanneer multiply(5, 3)
, de parameters a
en b
ontvangen 5
en respectievelijk 3
waarden. De vermenigvuldiging wordt berekend zoals verwacht: 5 * 3 = 15
.
Wat gebeurt er als je een argument bij aanroep weglaat? De corresponderende parameter binnen de functie wordt undefined
.
Laten we het vorige voorbeeld enigszins aanpassen door de functie aan te roepen met slechts één argument:
De aanroep multiply(5)
wordt uitgevoerd met één argument: als resultaat a
parameter is 5
, maar de b
parameter is undefined
.
Tip 6: gebruik de standaard parameterwaarde
Soms vereist een functie niet de volledige set argumenten bij het aanroepen. U kunt standaardwaarden instellen voor parameters die geen waarde hebben.
Laten we terugdenken aan het vorige voorbeeld, laten we een verbetering aanbrengen. Als de b
parameter undefined
is, laat deze dan standaard 2
:
De functie wordt aangeroepen met een enkel argument multiply(5)
. Aanvankelijk is de parameter a
2
en b
undefined
.
De voorwaardelijke instructie verifieert of b
undefined
is. Als dit gebeurt, stelt b = 2
-toewijzing een standaardwaarde in.
Hoewel de gegeven manier om standaardwaarden toe te wijzen werkt, raad ik af om rechtstreeks te vergelijken met undefined
. Het is uitgebreid en ziet eruit als een hack.
Een betere benadering is om de ES2015-functie voor standaardparameters te gebruiken. Het is kort, expressief en geen directe vergelijkingen met undefined
.
Het toevoegen van een standaardwaarde aan parameter b = 2
ziet er beter uit:
b = 2
in de functiehandtekening zorgt ervoor dat als b
undefined
is, de parameter is standaard 2
.
De functie voor standaardparameters van ES2015 is intuïtief en expressief. Gebruik het altijd om standaardwaarden voor optionele parameters in te stellen.
2.4 Functie retourwaarde
Impliciet, zonder
return
instructie, een JavaScript-functie geeftundefined
terug.
Een functie die geen return
statement retourneert impliciet undefined
:
retourneert geen berekeningsresultaten. Het resultaat van de functie-aanroep is undefined
.
Dezelfde situatie doet zich voor wanneer de instructie return
aanwezig is, maar zonder een expressie in de buurt:
return;
-instructie wordt uitgevoerd, maar het retourneert geen enkele uitdrukking. Het aanroepresultaat is ook undefined
.
Natuurlijk werkt het aangeven in de buurt van return
de uitdrukking die moet worden geretourneerd zoals verwacht:
Nu wordt de functie-aanroep geëvalueerd als 4
, wat 2
kwadraat is.
Tip 7: vertrouw het automatisch invoegen van puntkommas niet
De volgende lijst met uitspraken in JavaScript moet eindigen met puntkommas (;
) :
- lege verklaring
-
let
,const
,var
,import
,export
declaraties - uitdrukkingsverklaring
-
debugger
statement -
continue
statement,break
statement -
throw
statement -
return
statement
Als u een van de bovenstaande uitspraken gebruikt, zorg er dan voor dat u aan het einde een puntkomma aangeeft:
Aan het einde van beide let
declaratie en return
instructie wordt een verplichte puntkomma geschreven.
Wat gebeurt er als je deze niet wilt aangeven puntkommas? In een dergelijke situatie biedt ECMAScript een mechanisme voor automatisch invoegen van puntkommas (ASI), dat voor u de ontbrekende puntkommas invoegt.
Met behulp van ASI kunt u de puntkommas uit het vorige voorbeeld verwijderen:
De bovenstaande tekst is een geldige JavaScript-code. De ontbrekende puntkommas worden automatisch voor u ingevoegd.
Op het eerste gezicht ziet het er veelbelovend uit. Met het ASI-mechanisme kunt u de onnodige puntkommas overslaan. U kunt de JavaScript-code kleiner en gemakkelijker leesbaar maken.
Er is een kleine, maar irritante valstrik gemaakt door ASI. Wanneer een nieuwe regel tussen return
en de geretourneerde expressie return \n expression
staat, voegt ASI automatisch een puntkomma in voor de nieuwe regel return; \n expression
.
Wat betekent het binnen een functie om een return;
-instructie te hebben? De functie retourneert undefined
. Als u het mechanisme van ASI niet in detail kent, is het onverwacht geretourneerde undefined
misleidend.
Laten we bijvoorbeeld de geretourneerde waarde van getPrimeNumbers()
aanroep bestuderen:
Tussen de instructie return
en de letterlijke expressie van de array bestaat een nieuwe regel. JavaScript voegt automatisch een puntkomma in na return
, waarbij de code als volgt wordt geïnterpreteerd:
De instructie return;
zorgt ervoor dat de functie getPrimeNumbers()
undefined
retourneert in plaats van de verwachte array.
Het probleem is opgelost door de nieuwe regel tussen return
en letterlijke array te verwijderen:
Mijn aanbeveling is om te bestuderen hoe automatische puntkomma-invoeging precies werkt om dergelijke situaties te vermijden.
Plaats natuurlijk nooit een nieuwe regel tussen return
en de geretourneerde expressie.
2.5 void-operator
void <expression>
evalueert de uitdrukking en retourneert undefined
ongeacht het resultaat van de evaluatie.
Een gebruiksscenario van de void
-operator is het onderdrukken van expressie-evaluatie tot undefined
, vertrouwend op een neveneffect van de evaluatie.
3. undefined in arrays
Je krijgt undefined
wanneer je een array-element opent met een out of bounds index.
colors
array heeft 3 elementen, dus geldige indexen zijn 0
, 1
, en 2
.
Omdat er geen array-elementen op de indexen 5
en -1
staan, zijn de accessors colors
en colors
zijn undefined
.
In JavaScript kunt u zogenaamde sparse arrays tegenkomen. Dit zijn arrays met hiaten, d.w.z. bij sommige indexen zijn er geen elementen gedefinieerd.
Wanneer een gat (ook wel een leeg slot genoemd) wordt betreden binnen een sparse array, krijg je ook een undefined
.
Het volgende voorbeeld genereert sparse arrays en probeert toegang te krijgen tot hun lege slots:
sparse1
wordt gemaakt door een Array
constructor met een numeriek eerste argument.Het heeft 3 lege slots.
sparse2
is gemaakt met een letterlijke array met het ontbrekende tweede element.
In elk van deze spaarzame arrays resulteert toegang tot een lege ruimte in undefined
.
Wanneer u met arrays werkt, moet u, om undefined
te vermijden, ervoor zorgen dat u geldige array-indexen gebruikt en de creatie van sparse arrays voorkomt.
4. Verschil tussen ongedefinieerd en nul
Wat is het belangrijkste verschil tussen undefined
en null
? Beide speciale waarden impliceren een lege staat.
undefined
vertegenwoordigt de waarde van een variabele die nog niet is geïnitialiseerd, terwijlnull
vertegenwoordigt een opzettelijke afwezigheid van een object.
Laten we het verschil in enkele voorbeelden onderzoeken.
De variabele number
is gedefinieerd wordt echter niet toegewezen met een beginwaarde:
number
variabele is undefined
, wat een niet-geïnitialiseerde variabele aangeeft.
Hetzelfde niet-geïnitialiseerde concept doet zich voor wanneer een niet-bestaande objecteigenschap wordt benaderd:
Omdat lastName
eigenschap bestaat niet in obj
, JavaScript evalueert obj.lastName
naar undefined
.
Aan de andere kant weet je dat een variabele een object verwacht. Maar om de een of andere reden kunt u het object niet instantiëren. In dat geval is null
een betekenisvolle indicator van een ontbrekend object.
clone()
is bijvoorbeeld een functie die kloont een gewoon JavaScript-object. De functie retourneert naar verwachting een object:
clone()
kan echter worden aangeroepen met een niet-object-argument: 15
of null
. In dat geval kan de functie geen kloon maken, dus retourneert het null
– de indicator van een ontbrekend object.
typeof
operator maakt het onderscheid tussen undefined
en null
:
Ook de strikte kwaliteitsoperator ===
maakt correct onderscheid tussen undefined
van null
:
5. Conclusie
undefined
het bestaan is een gevolg van het tolerante karakter van JavaScript dat het gebruik van:
- niet-geïnitialiseerde variabelen
- niet-bestaande objecteigenschappen of -methoden
- indexen buiten het bereik om toegang te krijgen tot matrixelementen
- het aanroepresultaat van een functie die niets retourneert
Rechtstreeks vergelijken met undefined
is onveilig omdat u vertrouwt op een hierboven vermelde toegestane maar ontmoedigde praktijk.
Een efficiënte strategie is om het voorkomen van undefined
trefwoord in uw code minimaal te verminderen door goede gewoonten toe te passen, zoals:
- verminder het gebruik van niet-geïnitialiseerde variabelen
- maak de levenscyclus van de variabelen kort en dicht bij de bron van hun gebruik
- wijs waar mogelijk initiële waarden toe aan variabelen
- geef de voorkeur aan
const
, gebruik anderslet
- gebruik standaardwaarden voor onbeduidende functieparameters
- verifieer de eigenschappen bestaan of vul de onveilige objecten met standaardeigenschappen
- vermijd het gebruik van schaarse arrays
Is het goed dat JavaScript beide undefined
en null
om lege waarden weer te geven?