om du är ny på JavaScript är chansen att du redan har stött på något av det roliga beteendet som detta språk har att erbjuda (utställning a). I början, dessa konstiga egenheter kan verka löjligt och frustrerande, men jag lovar att det finns en metod bakom allt detta galenskap.
en av de svåraste hindren att övervinna, enligt min ödmjuka åsikt, är skillnaden mellan att passera genom värde vs att passera genom referens. Varför är detta koncept så knepigt? Till att börja med kan du säkert komma ganska långt utan att verkligen förstå hur JavaScript interagerar med primitiva värden och referensvärden. Detta kan, och oftare än inte, kommer att resultera i massor av buggar som är svåra att spåra och irriterande att fixa. För det andra är detta ett koncept som kommer att komma upp i tekniska intervjuer, så att inte förstå det kommer att räknas som en stor röd flagga mot dig.
Frukta inte, medläsare! Låt utbildningen börja …
primitiva datatyper
i JavaScript kan vi dela upp datatyper i två olika hinkar, primitiva datatyper och objekt.
det finns sex primitiva datatyper i JavaScript: string
, number
, boolean
, undefined
, null
, och symbol
från och med ES6.
primitiva datatyper skickas eller kopieras efter värde och är oföränderliga, vilket innebär att det befintliga värdet inte kan ändras hur en array eller ett objekt kan. Låt oss ta en titt på koden nedan för att se detta i aktion.
här har vi skapat två variabler, x = 10
och y = x
. Eftersom 10
är ett tal och ett primitivt värde, när vi ställer in y = x
kopierar vi faktiskt värdet, dvs 10
, och tilldelar det till y
. Vi kan också visualisera detta med hjälp av diagrammet nedan.
om vi skulle ändra värdet på x
skulle vi se att y
behåller sitt värde på 10
. Återigen beror detta på att primitiva värden kopieras, så y
värde är oberoende av x
värde. Tänk på det som att göra en kopia av en bild. När du har gjort kopian har du två identiska bilder: ett original och en fax. Om du skulle skära originalet i hälften skulle bara originalet ändras och faxen skulle förbli exakt densamma.
referensobjekt
objekt skickas å andra sidan genom referens och pekar på en plats i minnet för värdet, inte själva värdet. Låt oss ta en titt på detta i vår kod.
i det här exemplet är x
nu ett objekt som pekar på {dog: "poodle"}
. När vi skapar variabeln y
och tilldelar den värdet x
, kan vi nu utnyttja de olika egenskaperna hos x
som inkluderar värdet för dog
, dvs "poodle"
. Det verkar som exakt samma logik som används för primitiva värden, men låt oss ta en titt på vårt handy-dandy-diagram nedan för att se den subtila men viktiga skillnaden.
nu ser det här diagrammet lite annorlunda ut än när våra variabler x
och y
höll primitiva datatyper. I den här versionen ser vi att värdena för både x
och y
inte är datatyper utan referenser till en adress i minnet, samma adress faktiskt! Låt oss nu titta på vad som händer med x
om vi lägger till en ny egenskap av size
till y
…
x
returnerar fortfarande ett objekt men nu har det en extra egenskap av size
också! Återigen beror detta på att både x
och y
pekar på samma referensobjekt, så alla ändringar som görs i en variabel kommer att synas i den andra.
för att hjälpa mig att komma ihåg detta koncept gillar jag att tänka på referensvärden som ett hus och variablerna som människor som bor i det huset. Alla invånare (variabler) kan säga ”Jag har ett hus” och peka på samma hus. Om en enda invånare bestämmer sig för att de vill måla huset gult, har alla invånare nu ett gult hus eftersom det delas.
Låt oss ta en titt på ytterligare ett exempel som innehåller en mängd referensobjekt.
i den här koden börjar vi med en variabel person
som innehåller egenskaper name
, age
och hobbies
. När vi skriver ut det här objektet till konsolen får vi exakt vad vi förväntar oss — samma objekt som vi just skapade.
därefter har vi en funktion som heter changePerson
som tar in ett argument, gör några ändringar och returnerar sedan ett objekt. När vi skapar variabeln thirdPerson
, åberopar vi funktionenchangePerson
genom att skicka vårt ursprungliga objekt av person
in i den. Den intressanta biten är vad som händer när vi skriver ut till konsolen thirdPerson
och person
igen.
Observera att console.log(thirdPerson)
returnerar ett helt nytt objekt med nya egenskaper. Titta nu på vad console.log(person)
returnerar. Detta liknar vårt ursprungliga objekt men det innehåller nya egenskapsvärden som introducerades i vår changePerson
– funktion.
kontrollera jämlikhet
slutligen, låt oss ta en titt på hur primitiva datatyper och referensobjekt beter sig med jämställdhetsoperatörer.
när det gäller primitiva datatyper spelar det ingen roll vad som är till höger om =
– tecknet så länge värdena är desamma. Vi kan se detta ovan med variabler a
och b
som skrivs annorlunda men utvärderar till samma värde när vi använder ===
, den strikta jämställdhetsoperatören.
motsatsen är sant i det andra exemplet för dog
och cat
. Även om det kan tyckas att de innehåller identiska värden, är en array och ett referensobjekt, vilket betyder att
===
kontrollerar om både dog
och cat
har samma referens till värdet i minnet. Å andra sidan är bird === dog
sant eftersom de delar samma referensobjekt.
slutsats
och det avslutar vår introduktion till pass by value vs pass by reference. Det finns fler ämnen som kan täckas under detta paraply grundläggande, inklusive vad som händer när en referens skrivs över eller förloras, hur man kopierar en referens för att skapa ett nytt objekt och se till att kopian är en djup kopia, bara för att nämna några. Jag skulle rekommendera att kolla in de resurser jag använde nedan som går in i några av dessa ytterligare ämnen mer detaljerat.