Czy (a == 1 && a == 2 && a == 3) może kiedykolwiek mieć wartość true?


2484

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ć truew 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.


9
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
deceze

109
Dla ludzi, którzy najwyraźniej zagłosowali za zbyt szerokim : czy to jest wykopalisko w Javascript, które mówi, że jest zbyt wiele poprawnych odpowiedzi?
tomsmeding

24
Niektórzy ludzie siedzą wokół i filozofują, co jest możliwe. Inni koncentrują swoje wysiłki na tym, czy budują realne, poprawne biznesowo produkty dla swoich klientów. IMO, to pytanie nie ma praktycznej użyteczności poza tym, że nigdy nie powinieneś zadawać tego rodzaju pytań w wywiadzie ani pisać tego rodzaju kodu. Dlatego powinien zostać zamknięty. Naprawdę, czy firma zdaje sobie sprawę, że zapłacili komuś prawdziwe pieniądze, żeby usiąść i porozmawiać o tym?
P.Brian.Mackey,

15
Po przeczytaniu odpowiedzi morały tej historii są następujące: nie używaj, ==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.
Jesse C. Slicer

87
Uwaga moderatora: W historii przepełnienia stosu pojawiły się osoby, które odpowiedziały w różnych językach na ten, o którym mowa. Są to próby odpowiedzi na pytanie, ponieważ stanowią rozwiązanie ogólnego problemu, aczkolwiek w innym języku. Powstrzymaj się od oznaczania ich jako „brak odpowiedzi”. Powiedziawszy to, prosimy również powstrzymać się od publikowania większej liczby odpowiedzi w różnych językach - istnieje powód, dla którego to pytanie jest specyficzne dla JavaScript, jak wskazano w komentarzach pod niektórymi z tych innych odpowiedzi, i jest powód, dla którego lubimy nasze pytania specyficzne dla języka tak pozostać.
BoltClock

Odpowiedzi:


3323

Jeśli skorzystasz z tego== , jak to działa , możesz po prostu utworzyć obiekt z funkcją niestandardową toString(lub valueOf), która zmienia to, co zwraca za każdym razem, gdy jest używany, tak aby spełniał wszystkie trzy warunki.

const a = {
  i: 1,
  toString: function () {
    return a.i++;
  }
}

if(a == 1 && a == 2 && a == 3) {
  console.log('Hello World!');
}


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, valueOfjeśli jest to możliwe, a jeśli nie, wywoła toString. Użyłem toStringw tym przypadku po prostu dlatego, że to, co przyszło mi do głowy, valueOfmiałoby większy sens. Gdybym zamiast tego zwrócił ciąg znaków toString, 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ą.


70
Czy możesz to osiągnąć, zmieniając domyślną valueOf()operację?
Sterling Archer

43
Tak, valueOf działa zamiast toString z tego samego powodu
Kevin B

4
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
deceze

13
Zgodnie z tym najpierw spróbuje się konwersji liczb, więc valueOfjest nieco lepiej.
Salman A

6
@Pureferret po lewej stronie porównania równości jest przedmiotem, a nie liczbą. To, że ten obiekt ma właściwość number i, nie przeszkadza silnikowi. ;)
tomsmeding

2057

Nie mogłem się oprzeć - pozostałe odpowiedzi są niewątpliwie prawdziwe, ale tak naprawdę nie można przejść obok następującego kodu:

var a = 1;
var a = 2;
var a = 3;
if(aᅠ==1 && a== 2 &&ᅠa==3) {
    console.log("Why hello there!")
}

Zwróć uwagę na dziwne odstępy w ifstwierdzeniu (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:

var a_ = 1;
var a = 2;
var _a = 3;
if(a_==1 && a== 2 &&_a==3) {
    console.log("Why hello there!")
}

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:

var a= 1;
var a‍= 2; //one zero-width character
var a‍‍= 3; //two zero-width characters (or you can use the other one)
if(a==1&&a‍==2&&a‍‍==3) {
    console.log("Why hello there!")
}


368
Sądząc po nieparzystych odstępach w pierwotnym pytaniu, myślę, że jest to DOKŁADNIE odpowiedź, której szukało pytanie w wywiadzie - wykorzystując znaki spacje, które wyglądają jak spacje. Dobre miejsce!
Baracus

18
@Baracus To RonJohn zauważył dziwne odstępy w swoim komentarzu do odpowiedzi Kevina, która przypomniała mi tę (okropną) technikę, więc nie mogę przypisać sobie uznania. Byłem trochę zaskoczony, że nikt jeszcze na to nie odpowiedział, ponieważ kilka lat temu krążyło po mojej pracy z powodu jakiegoś postu na blogu - do pewnego stopnia uznałem, że jest to dość powszechna wiedza.
Jeff

102
Oczywiście jest to zakazane jako standardowa luka , która dotyczy również wywiadów. [potrzebne źródło]
Sanchises

13
Biorąc pod uwagę pierwotne odstępy, może być jeszcze gorzej, tzn. var ᅠ2 = 3Zastosowano zmienną ; są więc trzy zmienne aᅠᅠ= 1, ᅠ2 = 3, a = 3( a␣ = 1, ␣2 = 3, a = 3tak, że (a␣==1 && a==␣2 && a==3))…
Holger

2
@ AL-zami w dwóch zmiennych występuje dodatkowy znak, który pokazuje się na ekranie jako spacja, ale jest interpretowany jako część identyfikatora, co oznacza, że ​​istnieją trzy oddzielne zmienne - a, a i a - dodatkowy znak to Hangul o połowie szerokości.
Jeff

620

TO JEST MOŻLIWE!

var i = 0;

with({
  get a() {
    return ++i;
  }
}) {
  if (a == 1 && a == 2 && a == 3)
    console.log("wohoo");
}

Używa gettera wewnątrz withinstrukcji, 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 ===.

  var i = 0;

  with({
    get a() {
      return ++i;
    }
  }) {
    if (a !== a)
      console.log("yep, this is printed.");
  }


65
Tak, próbowałem tego samego :) Tak więc poprawna odpowiedź w wywiadzie brzmiałaby: „To nie może się zdarzyć w moim kodzie, ponieważ nigdy nie używam with”.
Pointy,

7
@Pointy - I, programuję w trybie ścisłym, gdzie withnie jest to dozwolone.
jfriend00

6
@Pointy w przyjętej odpowiedzi robią coś podobnego bez, withwięc może się to zdarzyć
Jungkook

2
@jorrit nikt by nie użył ==. I ===zapobiega zaakceptowanej odpowiedzi
Jonas Wilms

4
@JonasW. Wiele osób nadal korzysta, ==ale nie widziałem, withodką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.
wortwart

516

Przykład bez getterów lub wartości:

a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);

Działa to, ponieważ ==wywołuje funkcję, toStringktóra wymaga .jointablic.

Inne rozwiązanie, za pomocą Symbol.toPrimitivektórego jest odpowiednikiem ES6 toString/valueOf:

let i = 0;
let a = { [Symbol.toPrimitive]: () => ++i };

console.log(a == 1 && a == 2 && a == 3);


9
without valueOf, cóż ... jest bardziej pośredni, ale w zasadzie to samo.
Jonas Wilms

11
Naprawdę podoba mi się to rozwiązanie, ponieważ nie zastępujesz niczego oprócz własnej funkcji łączenia obiektów, a jest to po prostu bardzo czysty i łatwy do odczytania hack, który sprawia, że ​​logika jest oceniana jako prawdziwa.
Alex Pedersen

28
Szczerze mówiąc, myślę, że to najlepsza odpowiedź. Nie wymaga niczego niezwykłego, wystarczy ustawić kilka wartości. Bardzo łatwy do zrozumienia nawet przy podstawowej wiedzy o JS. Dobra robota.
Zac Delventhal

14
Ma to tak duży sens, że prawie wydaje się przydatne.
Andrew

7
Wiedziałem, że większość odpowiedzi byłaby o nadużywanie toStringlub valueOfale ten złapał mnie zupełnie nie warty. Bardzo sprytne i nie wiedziałem, że to zadzwoniło .joinwewnętrznie, ale ma to sens.
GBarroso,

268

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.

with({
  get a() {
    return Math.floor(Math.random()*4);
  }
}){
  for(var i=0;i<1000;i++){
    if (a == 1 && a == 2 && a == 3){
      console.log("after " + (i+1) + " trials, it becomes true finally!!!");
      break;
    }
  }
}


102
Celowo udzieliłbym tej odpowiedzi, nawet gdybym znał inne rozwiązania, ponieważ odpowiada ona na pytanie, ale oczywiście nie jest to, o co im chodziło. Graj w głupie gry, wygrywaj głupie nagrody.
ESR

2
Ale co, jeśli zajmie to ponad 1000 prób?
Piyin

9
@Piyin Jeśli zajmie to więcej niż 1000 prób, wygrasz nagrodę!
Skeets

5
Podoba mi się ta odpowiedź, ponieważ doprowadzenie do skrajności sugeruje, że jest to możliwe w każdym języku, jeśli rejestry / pamięć podręczna procesora zostaną trafione wystarczającą ilością promieni kosmicznych podczas działania programu lub jeśli ktoś celowo wykona usterkę mocy, tak że gałąź awarii jeśli warunkowy tak naprawdę nie skacze.
Ponkadoodle

Najniższy: 1, najwyższy: 412.
KyleFairns

210

Jeśli nie możesz nic zrobić bez wyrażeń regularnych:

var a = {
  r: /\d/g, 
  valueOf: function(){
    return this.r.exec(123)[0]
  }
}

if (a == 1 && a == 2 && a == 3) {
    console.log("!")
}

Działa z powodu niestandardowej valueOfmetody, która jest wywoływana, gdy Object jest porównywany z pierwotną (taką jak Number). Główna sztuczka polega na tym, że a.valueOfzwraca nową wartość za każdym razem, ponieważ wywołuje execwyrażenie regularne z gflagą, co powoduje aktualizację lastIndextego wyrażenia regularnego za każdym razem, gdy zostanie znalezione dopasowanie. Tak więc po raz pierwszy this.r.lastIndex == 0, to pasuje 1i aktualizacje lastIndex: this.r.lastIndex == 1, więc następnym razem regex będą pasować 2i tak dalej.


22
@Abdillah obiekt wyrażenia regularnego zapamięta ostatni indeks, do którego pasuje, execponowne wywołanie rozpocznie wyszukiwanie od tego indeksu. MDN nie jest bardzo jasne.
Simon Chan,

Rozumiem, więc this.robiekt wyrażenia regularnego zapamiętuje stan / indeks. Dzięki!
Abdillah

execPoleciłbym jednak przekazać ciąg znaków , a nie liczbę całkowitą, która ma być poddana strunowaniu.
Bergi,

użyj wyrażenia regularnego, a teraz masz dwa problemy
Aleksey Solovey

191

Można to osiągnąć za pomocą następujących opcji w zakresie globalnym. Do nodejsużytku globalzamiast windoww poniższym kodzie.

var val = 0;
Object.defineProperty(window, 'a', {
  get: function() {
    return ++val;
  }
});
if (a == 1 && a == 2 && a == 3) {
  console.log('yay');
}

Ta odpowiedź narusza niejawne zmienne dostarczone przez zakres globalny w kontekście wykonania, definiując moduł pobierający w celu pobrania zmiennej.


Zakłada się, że ajest to właściwość, thisktórej się nie wydaje. Gdyby abyła zmienną lokalną (jak to wygląda), to nie działałoby.
jfriend00

1
@ jfriend00 masz na myśli, jeśli umieściłeś var a; gdzieś?
jontro

Tak. Odwołanie a == 1sugeruje, że ajest 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 alub let aoznacza, że ​​nie ma thistakiej, która pozwala na dostęp ajako 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.
jfriend00

@ jfriend00 na pewno. Nie jestem pewien, czy przyniosłoby to znacznie więcej wartości w połączeniu z innymi odpowiedziami już. Zaktualizuje odpowiedź
jontro

14
Pytanie brzmiało: czy to „kiedykolwiek” może być prawdą. Odpowiedź brzmi „tak” i jest to jeden ze scenariuszy, w których może być prawdziwa: anie jest zmienną lokalną i jest zdefiniowana w zakresie globalnym za pomocą modułu zwiększającego.
Zac

190

Jest to możliwe w przypadku adostę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ą atylko w czasie, więc warunki a==1, a==2i a==3są 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

// Main Thread

const worker = new Worker('worker.js')
const modifiers = [new Worker('modifier.js'), new Worker('modifier.js')] // Let's use 2 workers
const sab = new SharedArrayBuffer(1)

modifiers.forEach(m => m.postMessage(sab))
worker.postMessage(sab)

worker.js

let array

Object.defineProperty(self, 'a', {
  get() {
    return array[0]
  }
});

addEventListener('message', ({data}) => {
    array = new Uint8Array(data)
    let count = 0
    do {
        var res = a == 1 && a == 2 && a == 3
        ++count
    } while(res == false) // just for clarity. !res is fine
    console.log(`It happened after ${count} iterations`)
    console.log('You should\'ve never seen this')
})

modifier.js

addEventListener('message' , ({data}) => {
    setInterval( () => {
        new Uint8Array(data)[0] = Math.floor(Math.random()*3) + 1
    })
})

Na moim MacBooku Air dzieje się to po około 10 miliardach iteracji przy pierwszej próbie:

wprowadź opis zdjęcia tutaj

Drugie podejście:

wprowadź opis zdjęcia tutaj

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 == 2i zmień Math.random()*3na Math.random()*2. Dodanie coraz większej liczby do listy zmniejsza szansę na trafienie.


50
Szczerze mówiąc, to najlepsza odpowiedź. Wszystkie pozostałe odpowiedzi wymagają celowej próby zrobienia czegoś głęboko nieintuicyjnego. Ta odpowiedź w rzeczywistości odzwierciedla coś, co może się zdarzyć w prawdziwym świecie - warunek wyścigu.
Tom Swirly,

34
Mało tego - widziałem, jak to się dzieje w prawdziwym świecie. Nie z dokładnym warunkiem w pytaniu, ale na pewno ze sprawdzeniem (a == 1) na początku funkcji i (a == 2) później w funkcji, i kodem trafiającym oba warunki. Do Twojej wiadomości, pierwszy raz zobaczyłem, że tak się dzieje w sterowniku silnika samochodowego, i wprowadziliśmy standardy kodowania. Drugi raz był w systemie dozownika sieczki i pochodni dla samolotów wojskowych i już pierwszego dnia w firmie znalazłem to i naprawiłem, podczas gdy reszta zespołu wciąż dyskutowała o tym problemie. (Poziom Kudos: wysoki! :)
Graham

38
Więc pracowałeś nad „sterownikami silników samochodowych” oraz „systemami dozowników plew i flary”, które są zaprogramowane w javascript z pracownikami sieci? Nie sądzę, żebym znowu wyszedł na zewnątrz.
psaxton

12
@psaxton :) Oczywiście, że nie - ale mamy wielowątkowe oprogramowanie z udostępnionymi danymi. Jest to anty-wzorzec dla wszystkich wielowątkowych programów, niezwiązanych z Javascriptem ani z pracownikami sieci. Nie ma znaczenia, czy programujesz w asemblerze, Brainf * ck, Visual BASIC, C czy JavaScript - jeśli zrobisz to ze współużytkowanymi danymi w aplikacji wielowątkowej, zawsze zawiedzie.
Graham

4
Myślę, że jest to teraz skomplikowane opakowanie odpowiedzi @ jontro.
qntm

148

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).

(() => {
    "use strict";
    Object.defineProperty(this, "a", {
        "get": () => {
            Object.defineProperty(this, "a", {
                "get": () => {
                    Object.defineProperty(this, "a", {
                        "get": () => {
                            return 3;
                        }
                    });
                    return 2;
                },
                configurable: true
            });
            return 1;
        },
        configurable: true
    });
    if (a == 1 && a == 2 && a == 3) {
        document.body.append("Yes, it’s possible.");
    }
})();


61
Zauważ, że podejście polegające na użyciu gettera również działa ===, nie tylko ==.
Makyen

To rozwiązanie polega na thisbyciu globalnym obiektem w ciele funkcji strzałki.
Roy Tinker

@Midnightas Nie sklasyfikowałbym żadnych innych odpowiedzi jako „kod piramidy” .
Patrick Roberts

Zauważ, że działa to również w dowolnym porządku, prawda? Jak (a == 3 && a == 2 && a == 1)?
Johannes,

131

Alternatywnie możesz użyć do tego klasy i instancji do sprawdzenia.

function A() {
    var value = 0;
    this.valueOf = function () { return ++value; };
}

var a = new A;

if (a == 1 && a == 2 && a == 3) {
    console.log('bingo!');
}

EDYTOWAĆ

Przy użyciu klas ES6 wyglądałoby to tak

class A {
  constructor() {
    this.value = 0;
    this.valueOf();
  }
  valueOf() {
    return this.value++;
  };
}

let a = new A;

if (a == 1 && a == 2 && a == 3) {
  console.log('bingo!');
}


5
dopiero function A() {value = 0;na początku?
Dave C

valueOfjest zastępowane, this method is usually called automatically by JavaScript behind the scenes, and not explicitly in codewięc gdy porównamy wartość, to faktycznie zwiększa ..
Danyal Sandeelo

130

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.

var a = 1;
var  = 2;
var а = 3;
if(a == 1 &&  == 2 && а == 3) {
    console.log("Why hello there!")
}

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 A
- Pełna szerokość Łacińska mała litera A
а - Cyrylica mała A

Ogó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) vs wikipedia.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.


19
„Nieznaczna rozbieżność” nie tak bym to nazwał.

4
@hvd Całkowicie zależy od renderowania czcionek. Oto co widzę .
Draco18s nie ufa już SE

1
@Jake Tak, pełna litera łacińska A nie jest największym homoglifem (ale warianty wielkich liter są niesamowite). Ogólnie jednak potrzebujesz tylko dwóch, aby uzyskać pożądany efekt.
Draco18s nie ufa już SE 17'18

@ Draco18s zgodził się ponownie: zwykle tylko 2 są potrzebne. Dobra robota, jeśli chodzi o dodatkowe informacje!
JakeSteam

10
Możesz również użyć selektora wariantów Unicode (U + FE00..U + FE0F). Żaden z nich to a: a︀ a︁ a︂. Nigdy więcej martwienia się o rozbieżności.
Salman A

108

Tak to mozliwe! 😎

»JavaScript

if‌=()=>!0;
var a = 9;

if‌(a==1 && a== 2 && a==3)
{
    document.write("<h1>Yes, it is possible!😎</h1>")
}

Powyższy kod jest krótką wersją (dzięki @Forivin za notatkę w komentarzach), a następujący kod jest oryginalny:

var a = 9;

if‌(a==1 && a== 2 && a==3)
{
    //console.log("Yes, it is possible!😎")
    document.write("<h1>Yes, it is possible!😎</h1>")
}

//--------------------------------------------

function if‌(){return true;}

Jeśli po prostu widzisz górną część mojego kodu i uruchamiasz go, mówisz WOW, jak?

Myślę więc, że wystarczy powiedzieć Tak, możliwe jest, że ktoś powiedział ci: Nic nie jest niemożliwe

Sztuczka: Użyłem ukrytego znaku po, ifaby stworzyć funkcję, której nazwa jest podobna if. W JavaScript nie możemy przesłonić słów kluczowych, więc zmusiłem się do użycia w ten sposób. To podróbka if, ale w tym przypadku działa dla Ciebie!


» C #

Napisałem również wersję C # ( z techniką zwiększania wartości nieruchomości ):

static int _a;
public static int a => ++_a;

public static void Main()
{
    if(a==1 && a==2 && a==3)
    {
        Console.WriteLine("Yes, it is possible!😎");
    }
}

Demo na żywo


56
Wersja javascript jest prawdziwą zbrodnią przeciwko ludzkości, a jej zdolność powinna być nielegalna na mocy konwencji ONZ. Myślę, że najwyższy czas oczyścić świat z wszelkiej wiedzy o javacript.
Jaśniejsze

2
Deklaracja funkcji może być jeszcze krótsza. if‌=()=>!0
Forivin

4
Dlaczego do cholery używałeś document.write? To pewny sposób, aby nie zostać zatrudnionym bez względu na resztę odpowiedzi.
Cerbrus

3
@Cerbrus, dziękuję za notatkę. Najpierw napisałem odpowiedź, console.logale zmieniłem ją na document.write. Naprawdę zawsze używam console.logw 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 przez console.log. Kliknij Run Code Snippetprzycisk 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.
RAM

1
@Clearer, jeśli Konwencje ONZ mogłyby skutecznie zmienić świat, powinniśmy mieć lepszy świat niż ten. Potrzebujemy czegoś więcej niż oświadczenia w ONZ i do tego dnia myślę, że możemy skorzystać z mojej sztuczki JavaScript;)
RAM

97

JavaScript

a == a +1

W JavaScript nie ma liczb całkowitych, ale tylkoNumber s, które są implementowane jako liczby zmiennoprzecinkowe podwójnej precyzji.

Oznacza to, że jeśli liczba ajest wystarczająco duża, można ją uznać za równą trzem kolejnym liczbom całkowitym:

a = 100000000000000000
if (a == a+1 && a == a+2 && a == a+3){
  console.log("Precision loss!");
}

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==3rozwiązania w Ruby i Python. Po niewielkiej modyfikacji jest to również możliwe w Javie.

Rubin

Z niestandardowym ==:

class A
  def ==(o)
    true
  end
end

a = A.new

if a == 1 && a == 2 && a == 3
  puts "Don't do this!"
end

Lub rosnąca a:

def a
  @a ||= 0
  @a += 1
end

if a == 1 && a == 2 && a == 3
  puts "Don't do this!"
end

Pyton

class A:
    def __eq__(self, who_cares):
        return True
a = A()

if a == 1 and a == 2 and a == 3:
    print("Don't do that!")

Jawa

Możliwe jest zmodyfikowanie Integerpamięci podręcznej Java :

package stackoverflow;

import java.lang.reflect.Field;

public class IntegerMess
{
    public static void main(String[] args) throws Exception {
        Field valueField = Integer.class.getDeclaredField("value");
        valueField.setAccessible(true);
        valueField.setInt(1, valueField.getInt(42));
        valueField.setInt(2, valueField.getInt(42));
        valueField.setInt(3, valueField.getInt(42));
        valueField.setAccessible(false);

        Integer a = 42;

        if (a.equals(1) && a.equals(2) && a.equals(3)) {
            System.out.println("Bad idea.");
        }
    }
}

27
@ cᴏʟᴅsᴘᴇᴇᴅ: Java, JavaScript, potayto, potahto :) Jest już wystarczająco dużo dobrych odpowiedzi JS. Pomyślałem, że byłoby interesujące pokazać, jak można to zrobić w innych językach i być może dać programistom JS kilka pomysłów.
Eric Duminil

2
@ cᴏʟᴅsᴘᴇᴇᴅ: Zaktualizowano z przykładem JS.
Eric Duminil

1
Dlaczego wersja Java nie działa Integer a = 42(lub nie działa)? Jak rozumiem, autoboxing, Integer a = 42; a == 1 && a == 2 && a == 3powinien zapakować wszystkie ints. A może to unbox a dla porównań?
97

@ CAD97: Integer == intwydaje się, że powoduje rozpakowanie. Ale użycie Integer#equals(int)wymusza autoboxing, więc działa. Dziękuję za komentarz!
Eric Duminil,

@StephanBijzitter: Proszę wyjaśnić. O ile mi wiadomo, są tylko Numbersw JS, które są w zasadzie jak doubles. 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ę, że n == n + 1może to być prawda dla liczb całkowitych w Javie / Python / C / Ruby / ...
Eric Duminil

80

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, 2i 3.

var  a = 1;
var 1 = a;
var 2 = a;
var 3 = a;
console.log( a ==ᅠ1 && a ==ᅠ2 && a ==ᅠ3 );

* 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:

var a = 1;
var a = 2;
var a = 3;
console.log(a == 1 && a == 2 && a == 3);

/****
var a = 1;
var a\u200c = 2;
var a\u200d = 3;
console.log(a == 1 && a\u200c == 2 && a\u200d == 3);
****/

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).


75

Zasada numer jeden podczas wywiadów; nigdy nie mów niemożliwe.

Nie potrzeba sztuczek z ukrytymi postaciami.

window.__defineGetter__( 'a', function(){
    if( typeof i !== 'number' ){
        // define i in the global namespace so that it's not lost after this function runs
        i = 0;
    }
    return ++i;
});

if( a == 1 && a == 2 && a == 3 ){
    alert( 'Oh dear, what have we done?' );
}


6
Auć. __defineGetter__tak naprawdę nie jest częścią języka js, tylko brzydką wersją defineProperty. typeofnie jest funkcją, a ta niezadeklarowana ijest po prostu okropna. Nadal wydaje się być wart 40 głosów pozytywnych: /
Jonas Wilms

6
@JonasW. 41 pozytywnych opinii :-) Wiem, że __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ć zamiast defineProperty()ponieważ starszy kod jest prawdziwy i nie można go zignorować. Niezależnie od brzydoty, deklarowanie iw taki sposób, jak ja to zrobiłem, jest dobrze znanym / udokumentowanym zachowaniem. Może właśnie byłem w nastroju na PCG ¯ \ _ (ツ) _ / ¯
MonkeyZeus

68

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.


13
Pytanie (lub wszystkie pytania na rozmowę kwalifikacyjną) ma prawdopodobnie przetestować gotowość kandydatów do myślenia o problemie, szczególnie tych, które są „pozornie oczywiste”, jak to. Ktoś, kto odmawia myślenia, ponieważ wierzy, że „wie”, że odpowiedź nie jest dobrym pomysłem.
Shammoo

5
@Don Hatch Nie, nie ukarałbym ich, gdyby odpowiedzieli w dobrej wierze, a zwłaszcza, jeśli udzieliliby prawidłowej odpowiedzi, jak pokazali inni ... ale poprosiłbym o dalsze działania, by spróbować sprawdzić, czy uważają dobry sposób na napisanie kodu lub nie. Bycie kompetentnym i umiejętność znalezienia „poprawnej” odpowiedzi to tylko część bycia dobrym programistą. Zdecydowanie ważniejsze dla „profesjonalnego” dewelopera jest pisanie zrozumiałego i łatwego w utrzymaniu kodu, często przez mniej zdolnych programistów. Zbyt sprytni programiści są tak samo źli jak niezdolni IME.
Frank W. Zammetti

16
To nie odpowiada na pytanie.
TylerH

6
Smutną rzeczą w tej odpowiedzi jest to, że użytkownik 1rep odpowiedział na to wczoraj i otrzymał 2 głosy negatywne, co spowodowało, że usunął to pytanie.
Jonas Wilms

8
@JohnColeman pytanie dotyczy sposobu, w jaki kod może zostać oceniony jako prawdziwy. Nie pyta o powody, dla których ankieter zaproponował pytanie. Ta odpowiedź nawet nie próbuje odpowiedzieć na zadane pytanie, a zamiast tego koncentruje się całkowicie na wersji „tego, co bym zrobił”, próby zgadnięcia, jaki był cel ankietera. Gdyby o to pytano, byłoby to zbyt szerokie. Dlatego ta odpowiedź nie należy tutaj ani nigdzie na stronie.
TylerH

43

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:

  1. 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 flgo Unicode „LATIN SMALL LIGATURE FL” (U + FB02)).

  2. 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 .

  3. 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:

  • Efekty uboczne mogą być naprawdę nieprzyjemne, a dobrze zaprojektowany program powinien być wolny od niepożądanych efektów ubocznych.
  • Stan wielowątkowy i zmienny może być problematyczny.
  • Niewłaściwe kodowanie znaków i przetwarzanie ciągów może prowadzić do nieprzyjemnych błędów.

1 Na przykład, można znaleźć przykład w zupełnie innym języku programowania (C #) wykazujący efekt uboczny (oczywisty) tutaj .


1
Wtedy pytanie staje się zbyt ogólne. Różne języki mogą to realizować z różnym stopniem łatwości. Pytanie zyskało tak dużą popularność, ponieważ jest to specyficzne pytanie JS, ale to tylko moje 2c.
cs95

1
przyczyny są różne C # i javascript, więc ta odpowiedź jest nieprawidłowa.
Edwin,

3
@Edwin: Przyczyny są dokładnie takie same: majsterkowanie w Unicode z podobnie wyglądającymi glifami lub znakami spacji, warunki wyścigu lub skutki uboczne operacji porównania (ta ostatnia jest pokazana w moim przykładzie).
Dirk Vollmar

2
@ cᴏʟᴅsᴘᴇᴇᴅ: Czasami patrzenie na rzeczy z szerszej perspektywy pomaga dostrzec rzeczywisty problem.
Dirk Vollmar

3
Chciałbym, aby tę odpowiedź można było przypisać do tego pytania w jakiś „meta” sposób. Po przeczytaniu wszystkich powyższych odpowiedzi czułem, że JS ma tak wiele dziur, ale podsumowałeś wszystkie odpowiedzi za jednym razem. I zrobiłeś to w sposób, który czyni z tego gwiezdne pytanie podczas wywiadu (jeśli tag specyficzny dla języka zostanie usunięty) moim zdaniem. Brawo!
KCE

41

Oto kolejna odmiana: użycie tablicy do usunięcia dowolnych wartości.

const a = {
  n: [3,2,1],
  toString: function () {
    return a.n.pop();
  }
}

if(a == 1 && a == 2 && a == 3) {
  console.log('Yes');
}


31

OK, kolejny hack z generatorami:

const value = function* () {
  let i = 0;
  while(true) yield ++i;
}();

Object.defineProperty(this, 'a', {
  get() {
    return value.next().value;
  }
});

if (a === 1 && a === 2 && a === 3) {
  console.log('yo!');
}


Mówisz hack, ale jestem całkiem pewien, że jest to przypadek użycia generatorów ... :) (no, z wyjątkiem tego, że polega to na thisbyciu obiektem okna)
Cody

29

Korzystanie z serwerów proxy :

var a = new Proxy({ i: 0 }, {
    get: (target, name) => name === Symbol.toPrimitive ? () => ++target.i : target[name],
});
console.log(a == 1 && a == 2 && a == 3);

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, agdy ==wymusza jej typ w celu porównania z każdym numerem. To się stało:

  1. Tworzymy obiekt docelowy { i: 0 }, w którymi właściwość jest naszym licznikiem
  2. Tworzymy serwer proxy dla obiektu docelowego i przypisujemy go do a
  3. Dla każdego a ==porównania atyp jest wymuszany na pierwotną wartość
  4. Ten rodzaj przymusu powoduje wywoływanie a[Symbol.toPrimitive]()wewnętrzne
  5. Serwer proxy przechwytuje pobranie a[Symbol.toPrimitive]funkcji za pomocą „get handler”
  6. „Dostać obsługi” kontrole pełnomocnika, że nieruchomość jest zdobyty jest 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:

var a = ...; // a.valueOf == target.i == 0
a == 1 && // a == ++target.i == 1
a == 2 && // a == ++target.i == 2
a == 3    // a == ++target.i == 3

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.


2
Nie ma jednak sensu używać do tego proxy - Symbol.toPrimitivetakie samo zdefiniowanie obiektu działałoby równie dobrze.
Ry-

27

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 ++:

#define a   (b++)
int b = 1;
if (a ==1 && a== 2 && a==3) {
    std::cout << "Yes, it's possible!" << std::endl;
} else {
    std::cout << "it's impossible!" << std::endl;
}

27
Nie sądzę, że jest to możliwe w każdym języku programowania. Na przykład nie wszystkie języki mają preprocesory. W tym przypadku nie wszystkie języki używają &&logicznych „i”.
Keith Thompson

3
Znalazłem sposób, który działa zarówno w Pythonie, jak i C ++, który wykorzystuje przeciążanie operatora.
Kaczor Donald

7
Możesz to zrobić w Javie, używając refleksji i psując pamięć podręczną liczb całkowitych.
97 CAD

7
Nie można tego zrobić w językach, które nie obsługują mutacji w tym miejscu, np. Nic nie jest dostępne w haskell
Jason Carr

4
Pytanie dotyczy JavaScript, a nie C ++.
Wszyscy pracownicy są niezbędni

26

To samo, ale inne, ale wciąż takie samo (może być „przetestowane” wiele razy):

const a = { valueOf: () => this.n = (this.n || 0) % 3 + 1}
    
if(a == 1 && a == 2 && a == 3) {
  console.log('Hello World!');
}

if(a == 1 && a == 2 && a == 3) {
  console.log('Hello World!');
}

Mój pomysł zaczął się od tego, jak działa równanie typu obiektu Number.


4
Działa również drugi raz!
Salman A

25

Odpowiedź ECMAScript 6, która korzysta z symboli:

const a = {value: 1};
a[Symbol.toPrimitive] = function() { return this.value++ };
console.log((a == 1 && a == 2 && a == 3));

Ze względu na ==użycie, JavaScript ma zmusić ado czegoś blisko drugiego argumentu ( 1, 2, 3w tym przypadku). Ale zanim JavaScript spróbuje samodzielnie wymusić wymuszenie, próbuje zadzwonić Symbol.toPrimitive. Jeśli podasz Symbol.toPrimitiveJavaScript, użyje wartości, którą zwróci twoja funkcja. Jeśli nie, JavaScript zadzwoni valueOf.


24

Myślę, że to minimalny kod do jego wdrożenia:

i=0,a={valueOf:()=>++i}

if (a == 1 && a == 2 && a == 3) {
  console.log('Mind === Blown');
}

Tworzenie obojętnego obiektu za pomocą niestandardowego parametru, valueOfktóry zwiększa globalną zmienną iprzy każdym wywołaniu. 23 znaki!


14

Ten wykorzystuje definProperty z przyjemnym efektem ubocznym powodującym zmienną globalną!

var _a = 1

Object.defineProperty(this, "a", {
  "get": () => {
    return _a++;
  },
  configurable: true
});

console.log(a)
console.log(a)
console.log(a)


8
możesz użyć zamknięcia a: get: (a => () => ++a)(0),globalne nie jest konieczne.
Nina Scholz

13
@NinaScholz na pewno, ale mówimy tutaj o złych praktykach - pozwól mi to mieć: D
Ben Aubin

1

Przesłaniając valueOfdeklarację klasy, można to zrobić:

class Thing {
    constructor() {
        this.value = 1;
    }

    valueOf() {
        return this.value++;
    }
}

const a = new Thing();

if(a == 1 && a == 2 && a == 3) {
    console.log(a);
}

To, co się dzieje, valueOfjest wywoływane w każdym operatorze porównania. W pierwszym abędzie równy 1, w drugim abędzie równy 2, i tak dalej, i tak dalej, ponieważ za każdym razem valueOfjest wywoływana, wartość ajest zwiększana.

Dlatego konsola.log uruchomi się i wyśle ​​(i tak w moim terminalu) Thing: { value: 4}, wskazując, że warunek był prawdziwy.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.