jeśli jesteś nowicjuszem w języku JavaScript, są szanse, że już natknąłeś się na Zabawne zachowanie, które ten język ma do zaoferowania (dowód a). Na początku te dziwne dziwactwa mogą wydawać się śmieszne i frustrujące, ale obiecuję, że za tym szaleństwem kryje się metoda.
jednym z najtrudniejszych przeszkód do pokonania, moim skromnym zdaniem, jest różnica między przechodzeniem przez wartość a przechodzeniem przez odniesienie. Dlaczego ta koncepcja jest tak skomplikowana? Na początek, z pewnością można zajść dość daleko bez naprawdę zrozumienia, jak JavaScript współdziała z prymitywnymi wartościami i wartościami referencyjnymi. To może, i częściej niż nie, spowoduje mnóstwo błędów, które są trudne do wyśledzenia i irytujące do naprawienia. Po drugie, jest to koncepcja, która pojawi się w wywiadach technicznych, więc niezrozumienie jej będzie się liczyć jako ogromna czerwona flaga przeciwko tobie.
nie bój się, kolego czytelniku! Let the education begin …
prymitywne typy danych
w JavaScript, możemy podzielić typy danych na dwa różne buckety, prymitywne typy danych i Obiekty.
w JavaScript jest sześć prymitywnych typów danych: string
, number
, boolean
, undefined
, null
, i symbol
od ES6.
prymitywne typy danych są przekazywane lub kopiowane przez wartość i są niezmienne, co oznacza, że istniejącej wartości nie można zmienić w sposób, w jaki tablica lub obiekt może. Rzućmy okiem na poniższy kod, aby zobaczyć to w akcji.
tutaj stworzyliśmy dwie zmienne, x = 10
i y = x
. Ponieważ 10
jest liczbą i prymitywną wartością, kiedy ustawiamy y = x
, tak naprawdę kopiujemy wartość, tj. 10
i przypisujemy ją do y
. Możemy to również zwizualizować, korzystając z poniższego wykresu.
jeśli mielibyśmy zmienić wartość x
, zobaczylibyśmy, że y
zachowuje swoją wartość 10
. Ponownie, dzieje się tak dlatego, że prymitywne wartości są kopiowane, więc wartość y
jest niezależna od wartości x
. Pomyśl o tym jak o zrobieniu kserokopii zdjęcia. Po wykonaniu kopii masz dwa identyczne zdjęcia: Oryginał i faksymile. Gdyby przeciąć oryginał na pół, tylko oryginał zostałby zmieniony, a faksymile pozostałyby dokładnie takie same.
obiekty referencyjne
obiekty, z drugiej strony, są przekazywane przez odniesienie i wskazują miejsce w pamięci dla wartości, a nie samą wartość. Spójrzmy na to w naszym kodzie.
w tym przykładzie x
jest teraz obiektem wskazującym na {dog: "poodle"}
. Kiedy tworzymy zmienną y
i przypisujemy jej wartość x
, jesteśmy teraz w stanie wykorzystać różne właściwości x
, które zawierają wartość dla dog
, czyli "poodle"
. Wydaje się, że jest to dokładnie ta sama logika używana dla prymitywnych wartości, ale rzućmy okiem na nasz wykres handy-dandy poniżej, aby zobaczyć subtelną, ale ważną różnicę.
teraz ten wykres wygląda nieco inaczej niż wtedy, gdy nasze zmienne x
i y
posiadały prymitywne typy danych. W tej wersji widzimy, że wartości zarówno dla x
, jak i y
nie są typami danych, ale odwołaniami do adresów w pamięci, w rzeczywistości tego samego adresu! Teraz rzućmy okiem na to, co dzieje się z x
, jeśli dodamy nową właściwość size
do y
…
x
nadal zwraca obiekt, ale teraz ma również dodatkową właściwość size
! Ponownie dzieje się tak dlatego, że zarówno x
, jak i y
wskazują ten sam obiekt odniesienia, więc wszelkie zmiany dokonane w jednej zmiennej będą widoczne w drugiej.
aby pomóc mi zapamiętać tę koncepcję, lubię myśleć o wartościach odniesienia jako domu i zmiennych jako ludzi, którzy mieszkają w tym domu. Wszyscy mieszkańcy (zmienne) mogą powiedzieć „mam dom” i wskazać ten sam dom. Jeśli jeden mieszkaniec zdecyduje, że chce pomalować dom na Żółto, to wszyscy mieszkańcy mają teraz żółty dom, ponieważ jest on wspólny.
przyjrzyjmy się jeszcze jednemu przykładowi, który zawiera różne obiekty odniesienia.
w tym kodzie zaczynamy od zmiennej person
, która zawiera właściwości name
, age
i hobbies
. Kiedy wydrukujemy ten obiekt na konsoli, otrzymamy dokładnie to, czego oczekujemy-ten sam obiekt, który właśnie stworzyliśmy.
następnie Mamy funkcję o nazwie changePerson
, która pobiera argument, wprowadza kilka zmian, a następnie zwraca obiekt. Kiedy tworzymy zmienną thirdPerson
, wywołujemy funkcjęchangePerson
przekazując do niej nasz oryginalny obiekt person
. Ciekawostką jest to, co się dzieje, gdy ponownie drukujemy na konsoli thirdPerson
i person
.
zauważ, że console.log(thirdPerson)
zwraca zupełnie nowy obiekt z nowymi właściwościami. Teraz spójrz, co zwraca console.log(person)
. Jest to podobne do naszego oryginalnego obiektu, ale zawiera nowe wartości właściwości, które zostały wprowadzone w naszej funkcji changePerson
.
sprawdzanie równości
na koniec przyjrzyjmy się, jak prymitywne typy danych i obiekty referencyjne zachowują się z operatorami równości.
jeśli chodzi o prymitywne typy danych, nie ma znaczenia, co znajduje się po prawej stronie znaku =
, o ile wartości są takie same. Widzimy to powyżej za pomocą zmiennych a
i b
, które są zapisane inaczej, ale obliczają tę samą wartość, gdy używamy ===
, operatora ścisłej równości.
przeciwieństwo jest prawdziwe w drugim przykładzie dla dog
i cat
. Chociaż może się wydawać, że zawierają one identyczne wartości, jest tablicą i obiektem odniesienia, co oznacza, że
===
sprawdza, czy zarówno dog
, jak i cat
mają to samo odniesienie do wartości w pamięci. Z drugiej strony, bird === dog
jest prawdziwe, ponieważ mają ten sam obiekt odniesienia.
wniosek
i to kończy nasze wprowadzenie do wartości pass by vs pass by reference. Istnieje więcej tematów, które mogą być objęte tym parasolem fundamental, w tym co się dzieje, gdy odniesienie jest nadpisane lub utracone, jak skopiować odniesienie, aby utworzyć nowy obiekt i upewnić się, że kopia jest głęboką kopią, by wymienić tylko kilka. Polecam sprawdzenie zasobów, z których korzystałem poniżej, które bardziej szczegółowo omawiają niektóre z tych dodatkowych tematów.