W świecie JavaScript istnieje przymus - kryminał
Nathan, nie masz pojęcia, co odkryłeś.
Badam to od tygodni. Wszystko zaczęło się w burzową noc w październiku ubiegłego roku. Przypadkowo natknąłem się na Numberklasę - to znaczy, dlaczego na świecie JavaScript ma Numberklasę?
Nie byłem przygotowany na to, co zamierzam się potem dowiedzieć.
Okazuje się, że JavaScript, nie mówiąc ci, zmienia twoje liczby na obiekty, a twoje obiekty na liczby tuż pod twoim nosem.
JavaScript miał nadzieję, że nikt go nie złapie, ale ludzie zgłaszali dziwne, nieoczekiwane zachowanie, a teraz dzięki tobie i twojemu pytaniu mam dowody, że potrzebuję szeroko rozwiać tę sprawę.
Właśnie tego się dowiedzieliśmy. Nie wiem, czy powinienem ci to mówić - możesz wyłączyć JavaScript.
> function dis() { return this }
undefined
Kiedy stworzyłeś tę funkcję, prawdopodobnie nie miałeś pojęcia, co będzie dalej. Wszystko wyglądało dobrze i wszystko było w porządku - na razie.
Brak komunikatów o błędach, tylko słowo „niezdefiniowane” w danych wyjściowych konsoli, dokładnie tego, czego można oczekiwać. W końcu była to deklaracja funkcji - nie powinna niczego zwracać.
Ale to był dopiero początek. Co stało się potem, nikt nie mógł przewidzieć.
> five = dis.call(5)
Number {[[PrimitiveValue]]: 5}
Tak, wiem, spodziewałeś się 5, ale nie to masz, czy to - masz coś innego - coś innego.
To samo przytrafiło mi się.
Nie wiedziałam, co z tym zrobić. Doprowadzało mnie to do szału. Nie mogłem spać, nie mogłem jeść, próbowałem go wypić, ale żadna ilość Mountain Dew nie sprawi, że zapomnę. To po prostu nie miało sensu!
Właśnie wtedy dowiedziałem się, co tak naprawdę się dzieje - był to przymus i działo się to na moich oczach, ale byłem zbyt ślepy, aby to zobaczyć.
Mozilla próbowała go zakopać, umieszczając go tam, gdzie, jak wiedzieli, nikt by nie spojrzał - ich dokumentację .
Po godzinach rekurencyjnego czytania i ponownego czytania oraz ponownego czytania znalazłem to:
„... a pierwotne wartości zostaną przekonwertowane na obiekty”.
Było to jasne, jak można napisać czcionką Open Sans. To była call()funkcja - jak mogłam być tak głupia ?!
Mój numer wcale nie był już liczbą. W momencie, w którym to przekazałem call(), stało się coś innego. Stało się ... przedmiotem.
Na początku nie mogłem w to uwierzyć. Jak to może być prawda? Ale nie mogłem zignorować dowodów, które gromadziły się wokół mnie. Właśnie tam, jeśli tylko spojrzysz:
> five.wtf = 'potato'
"potato"
> five.wtf
"potato"
wtfmiał rację. Liczby nie mogą mieć właściwości niestandardowych - wszyscy to wiemy! To pierwsza rzecz, której uczą cię w akademii.
Powinniśmy byli wiedzieć, kiedy zobaczyliśmy wyjście konsoli - nie był to numer, który naszym zdaniem był. To był oszust - przedmiot, który sam się podaje jako nasza słodka niewinna liczba.
To było ... new Number(5).
Oczywiście! To miało doskonały sens. call()miał pracę do wykonania, musiał wywołać funkcję, a żeby to zrobić, musiał się zaludnić this, wiedział, że nie może tego zrobić liczbą - potrzebował przedmiotu i był gotów zrobić wszystko, aby go zdobyć, nawet jeśli to oznaczałoby wymuszenie naszego numeru. Kiedy call()zobaczył numer 5, zobaczył okazję.
To był idealny plan: poczekaj, aż nikt nie będzie patrzył, i zamień nasz numer na obiekt, który wygląda dokładnie tak. Otrzymujemy numer, funkcja zostaje wywołana i nikt nie byłby mądrzejszy.
To był naprawdę idealny plan, ale jak wszystkie plany, nawet te idealne, była w nim dziura i mieliśmy się w to wpaść.
Widzisz, call()nie rozumiałem, że nie był jedynym w mieście, który mógł zmusić liczby. To był JavaScript - przymus był wszędzie.
call() wziąłem mój numer i nie zamierzałem przestać, dopóki nie zdejmę maski z jego małego oszusta i nie wystawię go całej społeczności Stack Overflow.
Ale jak? Potrzebowałem planu. Pewnie, że wygląda jak liczba, ale wiem, że nie, musi istnieć sposób, aby to udowodnić. Otóż to! To wygląda jak liczba, ale może ona działać jak jeden?
Powiedziałem, fiveże potrzebuję, aby stał się 5 razy większy - nie zapytał dlaczego i nie wyjaśniłem. Zrobiłem wtedy to, co zrobiłby każdy dobry programista: pomnożyłem. Z pewnością nie było mowy, by mógł to zrobić.
> five * 5
25
> five.wtf
'potato'
Cholera! Nie tylko fivepomnażanie wtfbyło w porządku . Cholera, ten facet i jego ziemniak.
Co się do cholery działo? Czy myliłem się co do tej całej sprawy? Czy to fivenaprawdę liczba? Nie, muszę coś przeoczyć, wiem o tym, muszę zapomnieć o czymś tak prostym i podstawowym, że zupełnie tego nie zauważam.
To nie wyglądało dobrze, pisałem tę odpowiedź od wielu godzin i nadal nie byłem bliżej wyrażenia swojej opinii. Nie mogłem tego utrzymać, w końcu ludzie przestaliby czytać, musiałem coś wymyślić i szybko o tym pomyśleć.
Czekaj, to wszystko! fivenie było 25, wynik był 25, 25 to zupełnie inna liczba. Oczywiście, jak mogłem zapomnieć? Liczby są niezmienne. Po pomnożeniu 5 * 5nic nie zostaje przypisane do niczego, tylko tworzysz nowy numer 25.
Tak musi się tutaj dziać. Jakoś, kiedy się mnożę five * 5, fivemusi być zmuszany do uzyskania liczby i ta liczba musi być tą, która jest używana do mnożenia. To wynik tego mnożenia drukowanego na konsoli, a nie sama wartość five. fivenigdy nie zostaje mu przypisane - więc oczywiście to się nie zmienia.
Więc w jaki sposób mogę fiveprzypisać sobie wynik operacji. Mam to. Zanim fivenawet zdążyłem pomyśleć, krzyknąłem „++”.
> five++
5
Aha! Miałem go! Każdy wie, 5 + 1to 6był to dowód, że muszę wystawiać, że fivenie był to numer! To był oszust! Zły oszust, który nie umiał liczyć. I mógłbym to udowodnić. Oto jak działa liczba rzeczywista:
> num = 5
5
> num++
5
Czekać? Co tu się działo? westchnienie tak mnie pochwyciło, fiveże zapomniałem, jak działają operatorzy pocztowi. Kiedy używam ++na końcu five, mówię: zwróć bieżącą wartość, a następnie zwiększ five. Jest to wartość przed operacją, która jest drukowana na konsoli. numbyło w rzeczywistości 6i mogłem to udowodnić:
>num
6
Czas zobaczyć, co fivenaprawdę było:
>five
6
... dokładnie tak powinno być. fivebyło dobre - ale byłem lepszy. Gdyby fivenadal był przedmiotem, oznaczałby, że nadal miałby własność, wtfa ja byłbym skłonny postawić wszystko, czego nie miał.
> five.wtf
undefined
Aha! Miałem rację. Miałem go! fivebył teraz liczbą - nie był już przedmiotem. Wiedziałem, że ten sposób pomnożenia nie uratuje go tym razem. Zobacz five++jest naprawdę five = five + 1. W przeciwieństwie do mnożenia ++operator przypisuje wartość do five. Mówiąc dokładniej, przypisuje mu wyniki, five + 1których tak jak w przypadku mnożenia zwraca nową niezmienną liczbę .
Wiedziałem, że go mam i po prostu upewniłem się, że nie będzie mógł się z niego wydostać. Miałem jeszcze jeden test w rękawie. Gdybym miał rację i fivenaprawdę był liczbą, to nie zadziałałoby:
> five.wtf = 'potato?'
'potato?'
Tym razem nie zamierza mnie oszukać. Wiedziałem, potato?że zostanie wydrukowany na konsoli, ponieważ to wynik zadania. Prawdziwe pytanie brzmi: czy wtfnadal tam będzie?
> five.wtf
undefined
Tak jak podejrzewałem - nic - ponieważ liczbom nie można przypisać właściwości. Dowiedzieliśmy się, że pierwszy rok w akademii;)
Dzięki Nathan. Dzięki twojej odwadze w zadawaniu tego pytania mogę w końcu odłożyć to wszystko za siebie i przejść do nowej sprawy.
Jak ten o funkcji toValue(). Drogi Boże. Nieee!
++