Uwaga moderatora: Oprzyj się potrzebie edycji kodu lub usunięcia tego powiadomienia. Wzór białych znaków może być częścią pytania i dlatego nie powinien być zmieniany niepotrzebnie. Jeśli jesteś w obozie „białe znaki są nieistotne”, powinieneś być w stanie zaakceptować kod w obecnej postaci.
Czy to możliwe, że (a== 1 && a ==2 && a==3)
można to ocenić true
w JavaScript?
To pytanie do wywiadu zadane przez dużą firmę technologiczną. Stało się to dwa tygodnie temu, ale wciąż próbuję znaleźć odpowiedź. Wiem, że nigdy nie piszemy takiego kodu w codziennej pracy, ale jestem ciekawy.
javascript
ecmascript-6
Dimpu Aravind Buddha
źródło
źródło
==
gdy masz na myśli===
, posiadaj standard kodowania, który zakazuje nazw zmiennych spoza ASCII, i zastosuj proces lintingu, który egzekwuje poprzednie dwie moralności.Odpowiedzi:
Jeśli skorzystasz z tego
==
, jak to działa , możesz po prostu utworzyć obiekt z funkcją niestandardowątoString
(lubvalueOf
), która zmienia to, co zwraca za każdym razem, gdy jest używany, tak aby spełniał wszystkie trzy warunki.Powodem tego jest użycie operatora luźnej równości. W przypadku korzystania z luźnej równości, jeśli jeden z operandów jest innego typu niż drugi, silnik podejmie próbę konwersji jednego na drugi. W przypadku obiektu po lewej stronie i numeru po prawej, spróbuje przekształcić obiekt w numer, najpierw wywołując,
valueOf
jeśli jest to możliwe, a jeśli nie, wywołatoString
. UżyłemtoString
w tym przypadku po prostu dlatego, że to, co przyszło mi do głowy,valueOf
miałoby większy sens. Gdybym zamiast tego zwrócił ciąg znakówtoString
, silnik próbowałby następnie przekonwertować ciąg znaków na liczbę, dając nam ten sam efekt końcowy, choć z nieco dłuższą ścieżką.źródło
valueOf()
operację?valueOf
jest nieco lepiej.i
, nie przeszkadza silnikowi. ;)Nie mogłem się oprzeć - pozostałe odpowiedzi są niewątpliwie prawdziwe, ale tak naprawdę nie można przejść obok następującego kodu:
Zwróć uwagę na dziwne odstępy w
if
stwierdzeniu (które skopiowałem z twojego pytania). Jest to Hangul o połowie szerokości (koreański dla tych, którzy nie znają), który jest znakiem spacji Unicode, który nie jest interpretowany przez skrypt ECMA jako znak spacji - oznacza to, że jest to poprawny znak identyfikatora. Dlatego istnieją trzy zupełnie różne zmienne, jedna z Hangulem po a, jedna z nim przed, a druga z tylko a. Ten_
sam kod, zastępując spację czytelnością, wyglądałby tak:Sprawdź sprawdzenie poprawności nazwy zmiennej Mathiasa . Jeśli to dziwne odstępy rzeczywiście zostały uwzględnione w ich pytaniu, jestem pewien, że jest to wskazówka dla tego rodzaju odpowiedzi.
Nie rób tego Poważnie.
Edit: Doszło do mojej uwagi, że (choć nie wolno rozpocząć zmiennej) Zero-szerokość stolarskie i Zero-szerokość non-stolarskie znaki są także dozwolone w nazwach zmiennych - patrz kasował JavaScript o zerowej szerokości znaków - plusy i minusy ?.
Wyglądałoby to następująco:
źródło
var ᅠ2 = 3
Zastosowano zmienną ; są więc trzy zmienneaᅠᅠ= 1, ᅠ2 = 3, a = 3
(a␣ = 1, ␣2 = 3, a = 3
tak, że(a␣==1 && a==␣2 && a==3)
)…TO JEST MOŻLIWE!
Używa gettera wewnątrz
with
instrukcji, aby pozwolića
ocenę do trzech różnych wartości.... to nadal nie oznacza, że należy tego używać w prawdziwym kodzie ...
Co gorsza, ta sztuczka będzie również działać przy użyciu
===
.źródło
with
”.with
nie jest to dozwolone.with
więc może się to zdarzyć==
. I===
zapobiega zaakceptowanej odpowiedzi==
ale nie widziałem,with
odkąd… no cóż, właściwie nigdy poza dokumentacją JS, w której jest napisane „proszę nie używać”. W każdym razie fajne rozwiązanie.Przykład bez getterów lub wartości:
Działa to, ponieważ
==
wywołuje funkcję,toString
która wymaga.join
tablic.Inne rozwiązanie, za pomocą
Symbol.toPrimitive
którego jest odpowiednikiem ES6toString/valueOf
:źródło
without valueOf
, cóż ... jest bardziej pośredni, ale w zasadzie to samo.toString
lubvalueOf
ale ten złapał mnie zupełnie nie warty. Bardzo sprytne i nie wiedziałem, że to zadzwoniło.join
wewnętrznie, ale ma to sens.Jeśli zostaniesz zapytany, czy jest to możliwe (nie MUSI), może poprosić „a” o zwrócenie losowej liczby. Byłoby prawdą, gdyby generował kolejno 1, 2 i 3.
źródło
Jeśli nie możesz nic zrobić bez wyrażeń regularnych:
Działa z powodu niestandardowej
valueOf
metody, która jest wywoływana, gdy Object jest porównywany z pierwotną (taką jak Number). Główna sztuczka polega na tym, żea.valueOf
zwraca nową wartość za każdym razem, ponieważ wywołujeexec
wyrażenie regularne zg
flagą, co powoduje aktualizacjęlastIndex
tego wyrażenia regularnego za każdym razem, gdy zostanie znalezione dopasowanie. Tak więc po raz pierwszythis.r.lastIndex == 0
, to pasuje1
i aktualizacjelastIndex
:this.r.lastIndex == 1
, więc następnym razem regex będą pasować2
i tak dalej.źródło
exec
ponowne wywołanie rozpocznie wyszukiwanie od tego indeksu. MDN nie jest bardzo jasne.this.r
obiekt wyrażenia regularnego zapamiętuje stan / indeks. Dzięki!exec
Poleciłbym jednak przekazać ciąg znaków , a nie liczbę całkowitą, która ma być poddana strunowaniu.Można to osiągnąć za pomocą następujących opcji w zakresie globalnym. Do
nodejs
użytkuglobal
zamiastwindow
w poniższym kodzie.Ta odpowiedź narusza niejawne zmienne dostarczone przez zakres globalny w kontekście wykonania, definiując moduł pobierający w celu pobrania zmiennej.
źródło
a
jest to właściwość,this
której się nie wydaje. Gdybya
była zmienną lokalną (jak to wygląda), to nie działałoby.a == 1
sugeruje, żea
jest gdzieś zmienną, a nie właściwościąthis
. Chociaż istnieje miejsce dziwne, takie jak globale, gdzie oba mogą być prawdziwe, ogólnie rzecz biorąc, zadeklarowanie zmiennej za pomocąvar a
lublet a
oznacza, że nie mathis
takiej, która pozwala na dostępa
jako właściwość, jak zakłada kod. Więc twój kod najwyraźniej zakłada dziwną zmienną globalną. Na przykład twój kod nie działa w node.js i nie jest w trybie ścisłym wewnątrz funkcji. Należy dokładnie określić okoliczności, w których to działa i prawdopodobnie wyjaśnić, dlaczego to działa. W przeciwnym razie jest to mylące.a
nie jest zmienną lokalną i jest zdefiniowana w zakresie globalnym za pomocą modułu zwiększającego.Jest to możliwe w przypadku
a
dostępu do zmiennej , powiedzmy 2 robotów internetowych za pośrednictwem SharedArrayBuffer, a także jakiegoś głównego skryptu. Możliwość jest niska, ale możliwe jest, że gdy kod jest kompilowany do kodu maszynowego, pracownicy internetowych zaktualizować zmiennąa
tylko w czasie, więc warunkia==1
,a==2
ia==3
są zadowoleni.Może to być przykład stanu wyścigu w środowisku wielowątkowym udostępnianym przez pracowników sieci Web i SharedArrayBuffer w JavaScript.
Oto podstawowa implementacja powyższego:
main.js
worker.js
modifier.js
Na moim MacBooku Air dzieje się to po około 10 miliardach iteracji przy pierwszej próbie:
Drugie podejście:
Jak powiedziałem, szanse będą niewielkie, ale biorąc pod uwagę wystarczającą ilość czasu, osiągną warunek.
Wskazówka: jeśli trwa zbyt długo w systemie. Spróbuj tylko
a == 1 && a == 2
i zmieńMath.random()*3
naMath.random()*2
. Dodanie coraz większej liczby do listy zmniejsza szansę na trafienie.źródło
Jest to również możliwe przy użyciu serii samozapisujących się programów pobierających:
(Jest to podobne do rozwiązania jontro, ale nie wymaga zmiennej licznika).
źródło
===
, nie tylko==
.this
byciu globalnym obiektem w ciele funkcji strzałki.(a == 3 && a == 2 && a == 1)
?Alternatywnie możesz użyć do tego klasy i instancji do sprawdzenia.
EDYTOWAĆ
Przy użyciu klas ES6 wyglądałoby to tak
źródło
function A() {value = 0;
na początku?valueOf
jest zastępowane,this method is usually called automatically by JavaScript behind the scenes, and not explicitly in code
więc gdy porównamy wartość, to faktycznie zwiększa ..Nie widzę już tej odpowiedzi, więc wrzucę ją również do miksu. Jest to podobne do odpowiedzi Jeffa z polem Hangula o połowie szerokości.
Możesz zauważyć niewielką rozbieżność z drugą, ale pierwsza i trzecia są identyczne z gołym okiem. Wszystkie 3 są odrębnymi znakami:
a
- Łacińska mała litera Aa
- Pełna szerokość Łacińska mała litera Aа
- Cyrylica mała AOgólny termin to „homoglyphs”: różne znaki unicode, które wyglądają tak samo. Zazwyczaj trudno jest zdobyć trzy, które są całkowicie nie do odróżnienia, ale w niektórych przypadkach możesz mieć szczęście. A, Α, А i Ꭺ działałyby lepiej (Latin-A, Greek Alpha , Cyrillic-A i Cherokee-A odpowiednio; niestety greckich i Cherokee małe litery są zbyt różni się od łacińskiego
a
:α
,ꭺ
i tak nie robi pomoc w powyższym fragmencie).Istnieje cała klasa ataków homoglyphów, najczęściej w fałszywych nazwach domen (np.
wikipediа.org
(Cyrylica) vswikipedia.org
(łacina)), ale może również pojawiać się w kodzie; zwykle określane jako podstępne (jak wspomniano w komentarzu, [podstępne] pytania są obecnie nie na temat PPCG , ale kiedyś były rodzajem wyzwania, w którym pojawiałyby się tego rodzaju rzeczy). Skorzystałem z tej witryny, aby znaleźć homoglyfy użyte w tej odpowiedzi.źródło
a
:a︀
a︁
a︂
. Nigdy więcej martwienia się o rozbieżności.Tak to mozliwe! 😎
»JavaScript
Powyższy kod jest krótką wersją (dzięki @Forivin za notatkę w komentarzach), a następujący kod jest oryginalny:
» C #
Napisałem również wersję C # ( z techniką zwiększania wartości nieruchomości ):
Demo na żywo
źródło
if=()=>!0
document.write
? To pewny sposób, aby nie zostać zatrudnionym bez względu na resztę odpowiedzi.console.log
ale zmieniłem ją na document.write. Naprawdę zawsze używamconsole.log
w swoich kodach, ale tutaj chcę tylko pokazać tekst użytkownikom w polu Fragment kodu StackOverflow. Więc chciałem pokazać moją wiadomość piękniejszą niż wiadomość wygenerowana przezconsole.log
. KliknijRun Code Snippet
przycisk mojej odpowiedzi i innych odpowiedzi. Fragment kodu SO pozwala mi używać html oraz JS i CSS, a następnie chciałem użyć go w swojej odpowiedzi i sprawić, by był przyjemny. Myślę, że to nie ma żadnego negatywnego skutku ubocznego i nie spowodowało, że moja odpowiedź była duża lub złożona.JavaScript
a == a +1
W JavaScript nie ma liczb całkowitych, ale tylko
Number
s, które są implementowane jako liczby zmiennoprzecinkowe podwójnej precyzji.Oznacza to, że jeśli liczba
a
jest wystarczająco duża, można ją uznać za równą trzem kolejnym liczbom całkowitym:To prawda, że nie jest to dokładnie to, o co pytał ankieter (nie działa
a=0
), ale nie wiąże się z żadną sztuczką z ukrytymi funkcjami lub przeciążeniem operatora.Inne języki
Dla porównania istnieją
a==1 && a==2 && a==3
rozwiązania w Ruby i Python. Po niewielkiej modyfikacji jest to również możliwe w Javie.Rubin
Z niestandardowym
==
:Lub rosnąca
a
:Pyton
Jawa
Możliwe jest zmodyfikowanie
Integer
pamięci podręcznej Java :źródło
Integer a = 42
(lub nie działa)? Jak rozumiem, autoboxing,Integer a = 42; a == 1 && a == 2 && a == 3
powinien zapakować wszystkie ints. A może to unbox a dla porównań?Integer == int
wydaje się, że powoduje rozpakowanie. Ale użycieInteger#equals(int)
wymusza autoboxing, więc działa. Dziękuję za komentarz!Numbers
w JS, które są w zasadzie jakdouble
s. Mogą wyglądać jak liczby całkowite i można ich używać jak liczb całkowitych, ale nadal nie są liczbami całkowitymi. Nie sądzę, żen == n + 1
może to być prawda dla liczb całkowitych w Javie / Python / C / Ruby / ...Jest to odwrócona wersja @ Jeffa odpowiedzi *, gdzie ukryty charakter (U + 115F, U + U + 1160 lub 3164) jest używany do tworzenia zmiennych, które wyglądają jak
1
,2
i3
.* Odpowiedź można uprościć, stosując łącznik zerowy (U + 200C) i łącznik zerowy (U + 200D). Oba te znaki są dozwolone w identyfikatorach, ale nie na początku:
Inne sztuczki są możliwe przy użyciu tego samego pomysłu, np. Przy użyciu selektorów wariacji Unicode do tworzenia zmiennych, które wyglądają dokładnie tak samo (
a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true
).źródło
Zasada numer jeden podczas wywiadów; nigdy nie mów niemożliwe.
Nie potrzeba sztuczek z ukrytymi postaciami.
źródło
__defineGetter__
tak naprawdę nie jest częścią języka js, tylko brzydką wersjądefineProperty
.typeof
nie jest funkcją, a ta niezadeklarowanai
jest po prostu okropna. Nadal wydaje się być wart 40 głosów pozytywnych: /__defineGetter__
jest przestarzała dla developer.mozilla.org/en-US/docs/Web/JavaScript/Reference /... ale wyraźnie działa w moim FireFoxie w wersji 57.0.4, więc zdecydowałem się to pokazać zamiastdefineProperty()
ponieważ starszy kod jest prawdziwy i nie można go zignorować. Niezależnie od brzydoty, deklarowaniei
w taki sposób, jak ja to zrobiłem, jest dobrze znanym / udokumentowanym zachowaniem. Może właśnie byłem w nastroju na PCG ¯ \ _ (ツ) _ / ¯Szczerze mówiąc, bez względu na to, czy istnieje sposób, aby ocenić to jako prawdziwe, czy nie (i jak wykazali inni, istnieje wiele sposobów), odpowiedź, której szukałam, mówiąc jako ktoś, kto przeprowadził setki wywiadów, byłaby coś w stylu:
„Cóż, może tak w dziwnych okolicznościach, które nie są dla mnie od razu oczywiste ... ale jeśli napotkałem to w prawdziwym kodzie, użyłbym typowych technik debugowania, aby dowiedzieć się, jak i dlaczego robi to, co robi a następnie natychmiast ponownie kodujemy, aby uniknąć takiej sytuacji ... ale co ważniejsze: absolutnie NIGDY nie napisałbym tego kodu w pierwszej kolejności, ponieważ jest to definicja zawiłego kodu, i staram się nigdy nie pisać skomplikowanego kodu ".
Wydaje mi się, że niektórzy ankieterzy obrażą się na wywołanie tego, co w oczywisty sposób ma być bardzo trudnym pytaniem, ale nie mam nic przeciwko programistom, którzy mają zdanie, szczególnie gdy mogą poprzeć to uzasadnioną myślą i mogą dopasować moje pytanie do znaczące oświadczenie o sobie.
źródło
Jeśli kiedykolwiek dostaniesz takie pytanie podczas rozmowy kwalifikacyjnej (lub zauważysz w swoim kodzie jakieś równie nieoczekiwane zachowanie), zastanów się, jakie rzeczy mogą spowodować zachowanie, które na pierwszy rzut oka wydaje się niemożliwe:
Kodowanie : W tym przypadku zmienna, na którą patrzysz, nie jest tą, o której myślisz, że jest. Może się to zdarzyć, jeśli celowo zepsujesz Unicode przy użyciu homoglyfów lub znaków spacji, aby nazwa zmiennej wyglądała jak inna, ale problemy z kodowaniem można również wprowadzić przypadkowo, np. Podczas kopiowania i wklejania kodu z Internetu zawierającego nieoczekiwany kod Unicode punktów (np. ponieważ system zarządzania treścią przeprowadził pewne „automatyczne formatowanie”, takie jak zastąpienie
fl
go Unicode „LATIN SMALL LIGATURE FL” (U + FB02)).Warunki wyścigu : A race-stan może wystąpić, czyli sytuacji, gdy kod nie jest wykonywany w kolejności oczekiwanej przez dewelopera. Warunki wyścigu często zdarzają się w kodzie wielowątkowym, ale wiele wątków nie jest warunkiem, aby warunki wyścigu były możliwe - asynchroniczność jest wystarczająca (i nie myl się, asynchronizacja nie oznacza, że wiele wątków jest używanych pod maską ).
Pamiętaj, że JavaScript nie jest wolny od warunków wyścigu tylko dlatego, że jest jednowątkowy. Widzieć tutaj prosty przykład jednowątkowy - ale asynchroniczny - przykład. W kontekście pojedynczego stwierdzenia warunki wyścigu byłyby jednak trudne do osiągnięcia w JavaScript.
JavaScript z robotami WWW jest nieco inny, ponieważ możesz mieć wiele wątków. @mehulmpt pokazał nam świetną weryfikację koncepcji przy użyciu pracowników sieci .
Efekty uboczne : efekt uboczny operacji porównywania równości (która nie musi być tak oczywista jak w przykładach tutaj, często skutki uboczne są bardzo subtelne).
Tego rodzaju problemy mogą pojawić się w wielu językach programowania nie tylko JavaScript, więc nie widzą jedną z klasycznych WTFs JavaScript tutaj 1 .
Oczywiście pytanie z wywiadu i próbki tutaj wyglądają na bardzo wymyślne. Ale są dobrym przypomnieniem, że:
1 Na przykład, można znaleźć przykład w zupełnie innym języku programowania (C #) wykazujący efekt uboczny (oczywisty) tutaj .
źródło
Oto kolejna odmiana: użycie tablicy do usunięcia dowolnych wartości.
źródło
OK, kolejny hack z generatorami:
źródło
this
byciu obiektem okna)Korzystanie z serwerów proxy :
Serwery proxy w zasadzie udają obiekt docelowy (pierwszy parametr), ale przechwytują operacje na obiekcie docelowym (w tym przypadku operację „pobierz właściwość”), dzięki czemu istnieje możliwość zrobienia czegoś innego niż domyślne zachowanie obiektu. W tym przypadku akcja „pobierz właściwość” jest wywoływana,
a
gdy==
wymusza jej typ w celu porównania z każdym numerem. To się stało:{ i: 0 }
, w którymi
właściwość jest naszym licznikiema
a ==
porównaniaa
typ jest wymuszany na pierwotną wartośća[Symbol.toPrimitive]()
wewnętrznea[Symbol.toPrimitive]
funkcji za pomocą „get handler”Symbol.toPrimitive
, w tym przypadku zwiększa go, a następnie zwraca licznik z obiektu docelowego:++target.i
. Jeśli pobierana jest inna właściwość, po prostu wracamy do zwracania domyślnej wartości właściwości,target[name]
Więc:
Podobnie jak w przypadku większości innych odpowiedzi, działa to tylko z luźną kontrolą równości (
==
), ponieważ ścisłe kontrole równości (===
) nie powodują przymusu typu, który może przechwycić serwer proxy.źródło
Symbol.toPrimitive
takie samo zdefiniowanie obiektu działałoby równie dobrze.W rzeczywistości odpowiedź na pierwszą część pytania brzmi „Tak” w każdym języku programowania. Na przykład dzieje się tak w przypadku C / C ++:
źródło
&&
logicznych „i”.To samo, ale inne, ale wciąż takie samo (może być „przetestowane” wiele razy):
Mój pomysł zaczął się od tego, jak działa równanie typu obiektu Number.
źródło
Odpowiedź ECMAScript 6, która korzysta z symboli:
Ze względu na
==
użycie, JavaScript ma zmusića
do czegoś blisko drugiego argumentu (1
,2
,3
w tym przypadku). Ale zanim JavaScript spróbuje samodzielnie wymusić wymuszenie, próbuje zadzwonićSymbol.toPrimitive
. Jeśli podaszSymbol.toPrimitive
JavaScript, użyje wartości, którą zwróci twoja funkcja. Jeśli nie, JavaScript zadzwonivalueOf
.źródło
Myślę, że to minimalny kod do jego wdrożenia:
Tworzenie obojętnego obiektu za pomocą niestandardowego parametru,
valueOf
który zwiększa globalną zmiennąi
przy każdym wywołaniu. 23 znaki!źródło
Ten wykorzystuje definProperty z przyjemnym efektem ubocznym powodującym zmienną globalną!
źródło
a
:get: (a => () => ++a)(0),
globalne nie jest konieczne.Przesłaniając
valueOf
deklarację klasy, można to zrobić:To, co się dzieje,
valueOf
jest wywoływane w każdym operatorze porównania. W pierwszyma
będzie równy1
, w drugima
będzie równy2
, i tak dalej, i tak dalej, ponieważ za każdym razemvalueOf
jest wywoływana, wartośća
jest zwiększana.Dlatego konsola.log uruchomi się i wyśle (i tak w moim terminalu)
Thing: { value: 4}
, wskazując, że warunek był prawdziwy.źródło