Czy (a== 1 && A ==2 && a==3) można kiedykolwiek ocenić na true?

Uwaga moderatora: Proszę oprzeć się pokusie edycji kodu lub usunięcia tego powiadomienia. Wzorzec spacji może być częścią pytania i dlatego nie powinien być niepotrzebnie modyfikowany. Jeśli znajdujesz się w obozie" Biała spacja jest nieistotna", powinieneś być w stanie zaakceptować kod w takim stanie, w jakim jest.

Czy jest kiedykolwiek możliwe, że (a== 1 && a ==2 && a==3) może ocenić do true w JavaScript?

To jest wywiad zadany przez dużą firmę technologiczną. Stało się to dwa tygodnie z powrotem, ale wciąż próbuję znaleźć odpowiedź. Wiem, że nigdy nie piszemy takiego kodu w naszej codziennej pracy, ale jestem ciekawa.
Author: BoltClock, 2018-01-15

25 answers

Jeśli wykorzystasz Jak działa == , możesz po prostu utworzyć obiekt z niestandardową funkcją toString (lub valueOf), która zmienia to, co zwraca za każdym razem, gdy jest używana, tak aby spełniała 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 działania jest użycie luźnego operatora równości. Podczas używania luźnej równości, jeśli jeden z operandów jest innego typu niż drugi, silnik będzie próbował przekonwertować jeden na drugi. W przypadek obiektu po lewej i liczby po prawej stronie, będzie próbował przekonwertować obiekt na liczbę przez pierwsze wywołanie valueOf, jeśli jest możliwe wywołanie, a w przeciwnym razie wywoła toString. Użyłem toString w tym przypadku po prostu dlatego, że to, co przyszło mi do głowy, valueOf miałoby więcej sensu. Gdybym zamiast tego zwrócił ciąg znaków z toString, silnik spróbowałby przekonwertować ciąg znaków na liczbę dającą nam ten sam efekt końcowy, choć z nieco dłuższą ścieżką.

 3121
Author: Kevin B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-18 23:07:07

Nie mogłem się oprzeć - inne odpowiedzi są niewątpliwie prawdziwe, ale 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 stwierdzeniu if (które skopiowałem z twojego pytania). Jest to Hangul o połowie szerokości (to po koreańsku dla nieznanych), który jest znakiem spacji Unicode, który nie jest interpretowany przez skrypt ECMA jako znak spacji - oznacza to, że jest to ważny znak dla identyfikatora. Dlatego istnieją trzy całkowicie różne zmienne, jedna z Hangul po a, jedna z nim przed i ostatnia z tylko a. zastępując spację _ dla czytelności, ten sam kod 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ź walidację nazwy zmiennej Mathias . Jeśli ten dziwny odstęp był rzeczywiście zawarty w ich pytaniu, jestem pewien, że jest to wskazówka dla tego rodzaju odpowiedzi.

Nie rób tego. Poważnie.

Edit: doszło do zwracam uwagę, że (chociaż nie wolno uruchamiać zmiennej) znaki zero-width joiner i zero-width non-joiner są również dozwolone w nazwach zmiennych-patrz zaciemnianie JavaScript ze znakami o zerowej szerokości-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!")
}
 1937
Author: Jeff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-25 19:47:49

TO 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 with, Aby a Oceniać na trzy różne wartości.

... to nadal nie oznacza, że powinno być używane w prawdziwym kodzie...

Co gorsza, ta sztuczka będzie działać również przy użyciu ===.

  var i = 0;

  with({
    get a() {
      return ++i;
    }
  }) {
    if (a !== a)
      console.log("yep, this is printed.");
  }
 575
Author: Jonas Wilms,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-05 10:09:38

Przykład bez getterów lub valueOf:

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

To działa, ponieważ == wywołuje toString, który wywołuje .join dla tablic.

Inne rozwiązanie, używając Symbol.toPrimitive, który jest odpowiednikiem ES6 toString/valueOf:

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

console.log(a == 1 && a == 2 && a == 3);
 441
Author: georg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-17 15:49:56

Jeśli zostanie zapytane, czy jest możliwe (nie musi), może poprosić "a" o zwrócenie liczby losowej. Byłoby to 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;
    }
  }
}
 252
Author: mmmaaa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-21 18:46:47

Kiedy nie można 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 ze względu na zwyczaj valueOf metoda, która jest wywoływana, gdy obiekt jest porównywany z primitive (np. Number). Główną sztuczką jest to, że a.valueOf zwraca nową wartość za każdym razem, ponieważ wywołuje {[3] } w wyrażeniu regularnym z flagą g, co powoduje aktualizację lastIndex tego wyrażenia regularnego za każdym razem, gdy zostanie znalezione dopasowanie. Więc pierwszy raz this.r.lastIndex == 0, pasuje 1 i aktualizuje lastIndex: this.r.lastIndex == 1, więc następnym razem regex będzie pasował 2 i tak dalej.

 197
Author: Kos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-18 09:37:01

Można to osiągnąć za pomocą następujących w zakresie globalnym. Dla nodejs Użyj global zamiast window w 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ź nadużywa ukrytych zmiennych dostarczanych przez globalny zakres w kontekście wykonywania, definiując getter do pobierania zmiennej.

 184
Author: jontro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-15 21:42:40

Jest to możliwe w przypadku, gdy zmienna a jest dostępna dla, powiedzmy 2 pracowników sieci poprzez SharedArrayBuffer, a także jakiś skrypt główny. Możliwość jest niska, ale jest możliwe, że gdy kod zostanie skompilowany do kodu maszynowego, pracownicy sieci aktualizują zmienną a w odpowiednim czasie, aby Warunki a==1, a==2 i a==3 są zadowoleni.

Może to być przykład stanu rasy w środowisku wielowątkowym dostarczanym przez pracowników sieci 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)

Pracownik.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')
})

Modyfikator.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:]}

Tutaj wpisz opis obrazka

Druga próba:

Tutaj wpisz opis obrazka

Jak powiedziałem, szanse będą niskie, ale biorąc pod uwagę wystarczająco dużo czasu, to osiągnie warunek.

Wskazówka: jeśli trwa to zbyt długo na Twoim system. Spróbuj tylko a == 1 && a == 2 i zmień Math.random()*3 na Math.random()*2. Dodawanie coraz więcej do listy zmniejsza szansę trafienia.

 175
Author: mehulmpt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-23 13:53:56

Jest to również możliwe przy użyciu serii getterów samo-nadpisują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.");
    }
})();
 142
Author: Patrick Dark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-18 09:30:38

Nie widzę jeszcze tej odpowiedzi, więc dorzucę też tę do miksu. Jest to podobne do odpowiedzi Jeffa z przestrzenią Hangul o połowie szerokości.

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

Można zauważyć niewielką rozbieżność z drugim, ale pierwszy i trzeci są identyczne gołym okiem. Wszystkie 3 są odrębnymi znakami:

a - łacińskie małe litery A
- pełna szerokość łacińskie małe litery A
а - Mała litera A

Nazwa rodzajowa dla tego jest "homoglify": różne znaki unicode, które wyglądają tak samo. Zazwyczaj trudno jest zdobyć trzy , które są zupełnie nie do odróżnienia, ale w niektórych przypadkach można mieć szczęście. A, Α, А i Ꭺ (łac.-a, Grecka Alfa, cyrylica-A i Cherokee-a; niestety małe litery greckie i Cherokee różnią się zbytnio od łacińskich a: α,, and so doesn't help with the above snippet).

There's an entire class of Homoglyph Attacks out there, most commonly in fake domain names (eg. wikipediа.org (cyrylicy) vs wikipedia.org (łac.)), ale może też pojawić się w kodzie; zazwyczaj określane jako bycie podszytym (jak wspomniano w komentarzu, [podszytym] pytania są teraz off-topic na PPCG , ale kiedyś były rodzajem wyzwania, w którym tego rodzaju rzeczy pojawiały się). Użyłem tej strony aby znaleźć homoglify użyte do tej odpowiedzi.

 125
Author: Draco18s,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-19 22:49:54

Alternatywnie możesz użyć klasy do tego 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!');
}

EDIT

Używając 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!');
}
 117
Author: Nina Scholz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-25 13:25:00

JavaScript

A == a +1

W JavaScript nie ma liczb całkowitych, ale tylko Numbers, które są zaimplementowane jako liczby zmiennoprzecinkowe o 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:

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

To prawda, nie jest to dokładnie to, o co pytała ankieter( nie działa z a=0), ale nie wiąże się z żadną sztuczką z ukrytymi funkcjami lub operatorem przeciążenie.

Inne języki

Dla odniesienia, istnieją a==1 && a==2 && a==3 rozwiązania w Ruby i Python. Z niewielką modyfikacją jest to również możliwe w Javie.

Ruby

Z obyczajem ==:

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ący a:

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

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

Python

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!")

Java

Możliwe jest modyfikowanie Javy Integer cache :

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.");
        }
    }
}
 88
Author: Eric Duminil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-21 18:50:30

Tak, to możliwe!

" 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 skróconą wersją (podziękowania dla @Forivin za uwagę 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 zobaczysz górną stronę mojego kodu i go uruchomisz, powiesz WOW, jak?

Więc myślę, że wystarczy powiedzieć Tak, możliwe jest komuś, kto powiedział do ty: Nie ma rzeczy niemożliwych

Trick: Użyłem ukrytego znaku po if, aby utworzyć funkcję, której nazwa jest podobna do if. W JavaScript nie możemy nadpisać słowa kluczowe, więc zmuszony do korzystania w ten sposób. Jest to podróbka if, ale w tym przypadku działa na Ciebie!


" C #

Napisałam też wersję C #(ze zwiększeniem wartości właściwości technic):

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!");
    }
}

Live Demo

 85
Author: RAM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-21 18:58:21

Jest to odwrócona wersja @Jeff ' s answer * gdzie ukryty znak (U+115F, u+1160 lub u+3164) jest używany do tworzenia zmiennych, które wyglądają jak 1, 2 i 3.

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

* ta odpowiedź może być uproszczona przez użycie elementu o zerowej szerokości (u+200C) i elementu o zerowej szerokości (U+200D). Oba te znaki są dozwolone wewnątrz identyfikatorów, 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 triki są możliwe przy użyciu tego samego pomysłu np. używając selektorów zmienności Unicode do tworzenia zmiennych, które wyglądają dokładnie tak samo (a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true).

 77
Author: Salman A,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-19 10:20:51

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

Nie ma potrzeby kombinowania 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?' );
}
 72
Author: MonkeyZeus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-19 17:24:13

Szczerze mówiąc, niezależnie od tego, czy jest sposób, aby to ocenić na prawdę, czy nie (i jak inni pokazali, istnieje wiele sposobów), odpowiedź, której bym szukał, mówiąc jako ktoś, kto przeprowadził setki wywiadów, byłaby czymś w stylu: {]}

"cóż, może tak w pewnych dziwnych okolicznościach, które nie są dla mnie oczywiste... ale gdybym natknął się na to w prawdziwym kodzie, użyłbym popularnych technik debugowania, aby dowiedzieć się, jak i dlaczego to robi co robi, a następnie natychmiast refaktor kod, aby uniknąć tej sytuacji... ale co ważniejsze: absolutnie nigdy nie napiszę tego kodu, ponieważ jest to sama definicja zawiłego kodu i staram się nigdy nie pisać zawiłego kodu".

Myślę, że niektórzy rozmówcy obraziliby się, że to, co oczywiście ma być bardzo podchwytliwym pytaniem, zostało wywołane, ale nie mam nic przeciwko deweloperom, którzy mają swoje zdanie, zwłaszcza gdy mogą je poprzeć uzasadnionym myślałem i mogę opisać moje pytanie w sensownym oświadczeniu o sobie.

 65
Author: Frank W. Zammetti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-16 21:57:37

Oto kolejna odmiana, używająca tablicy do wyświetlania 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');
}
 40
Author: Théophile,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-16 20:00:11

Jeśli kiedykolwiek otrzymasz takie pytanie podczas rozmowy kwalifikacyjnej (lub zauważysz równie nieoczekiwane zachowanie w kodzie) zastanów się, jakie rzeczy mogą spowodować zachowanie, które na pierwszy rzut oka wydaje się niemożliwe: {]}

  1. Encoding: w tym przypadku zmienna, na którą patrzysz, nie jest tą, którą myślisz, że jest. Może się to zdarzyć, jeśli celowo zadzierasz z Unicode używając homoglifów lub znaków spacji , aby nazwa zmiennej wyglądała jak inna jeden, ale problemy z kodowaniem mogą być również wprowadzone przypadkowo, np. podczas kopiowania i wklejania kodu z sieci, który zawiera nieoczekiwane punkty kodu Unicode (np. ponieważ system zarządzania treścią wykonał pewne "Autoformatowanie", takie jak zastąpienie fl Unicode ' LATIN SMALL LIGATURE FL '(U+FB02)).

  2. Race conditions : może wystąpić a race-condition , tzn. sytuacja, w której kod nie jest wykonywany w kolejności oczekiwanej przez programistę. Warunki wyścigowe często zdarza się w kodzie wielowątkowym, ale wiele wątków nie jest wymogiem, aby Warunki wyścigu były możliwe – asynchroniczność jest wystarczająca (i nie mylić, asynchroniczność nie oznacza, że wiele wątków jest używanych pod maską ).

    Zauważ, że dlatego JavaScript nie jest wolny od warunków rasowych tylko dlatego, że jest jednowątkowy. Zobacz tutaj dla prostego jednowątkowego – ale asynchronicznego-przykładu. W kontekście jednego stwierdzenia stan rasy jednak być raczej trudno trafić w JavaScript.

    JavaScript z Web workerami jest nieco inny, ponieważ można mieć wiele wątków. @mehulmpt pokazał nam wielki proof-of-concept przy użyciu Web workers .

  3. Efekty uboczne: efekt uboczny operacji porównywania równości (co nie musi być tak oczywiste jak w przykładach tutaj, często efekty uboczne są bardzo subtelne).

Tego typu problemy mogą pojawić się w wielu językach programowania, a nie tylko JavaScript, więc nie widzimy jednego z klasycznych JavaScript WTFs tutaj1.

Oczywiście, pytanie z wywiadu i próbki tutaj wyglądają bardzo wymyślne. Ale są one dobrym przypomnieniem, że:

  • efekty uboczne mogą być naprawdę nieprzyjemne i dobrze zaprojektowany program powinien być wolny od niepożądanych efektów ubocznych.
  • wielowątkowy i zmienny stan może być problematyczny.
  • nie wykonując kodowania znaków i przetwarzania ciągów znaków można prowadzić do paskudnych robaków.

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

 33
Author: Dirk Vollmar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-25 13:06:44

Dobra, 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!');
}
 30
Author: BaggersIO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-18 09:28:37

W rzeczywistości odpowiedź na pierwszą część pytania brzmi " tak " w każdym języku programowania. Na przykład, tak jest 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;
}
 26
Author: Gustavo Rodríguez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-17 15:40:18

Ten sam, ale inny, ale wciąż ten sam (może być" testowany " 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 liczbowego.

 25
Author: Preda7or,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-17 16:08:14

Using 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 zasadniczo udają obiekt docelowy( pierwszy parametr), ale przechwytywają operacje na obiekcie docelowym (w tym przypadku operacja "get property"), dzięki czemu istnieje możliwość zrobienia czegoś innego niż domyślne zachowanie obiektu. W tym przypadku akcja "get property" jest wywoływana na a, Gdy == wymusza jej typ w celu porównania jej z każdą liczbą. Dzieje się tak:

  1. tworzymy obiekt docelowy, { i: 0 }, gdzie i właściwość jest naszym licznikiem
  2. tworzymy Proxy dla obiektu docelowego i przypisujemy go do a
  3. dla każdego porównania a ==, typ a jest wymuszany do prymitywnej wartości
  4. ten typ wymuszenia powoduje wywołanie a[Symbol.toPrimitive]() wewnętrznie
  5. Proxy przechwytuje uzyskanie a[Symbol.toPrimitive] funkcji za pomocą "get handler"
  6. funkcja "get handler" serwera Proxy sprawdza, czy otrzymywana właściwość jest Symbol.toPrimitive, w którym to przypadku zwiększa się, 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

Jak w przypadku większości innych odpowiedzi, działa to tylko z luźnym sprawdzeniem równości (==), ponieważ ścisłe sprawdzanie równości (===) nie powoduje przymusu typu, który może przechwycić Proxy.

 24
Author: IceCreamYou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-21 18:56:15

Myślę, że jest to minimalny kod, aby go zaimplementować:

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

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

Tworzenie atrapy obiektu z niestandardowym valueOf, który zwiększa globalną zmienną i przy każdym wywołaniu. 23 znaki!

 21
Author: Gaafar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-22 06:27:48

Odpowiedź ECMAScript 6 wykorzystująca Symbole:

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 zmuszać a do czegoś Bliskiego drugiemu operandowi (1, 2, 3 w tym przypadku). Ale zanim JavaScript spróbuje samodzielnie wymyślić wymuszenie, próbuje wywołać Symbol.toPrimitive. Jeśli podasz Symbol.toPrimitive JavaScript użyje wartości zwracanej przez twoją funkcję. Jeśli nie, JavaScript wywoła valueOf.

 21
Author: Omar Alshaker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-21 18:51:59

Ten używa defineProperty z ładnym 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)
 10
Author: Ben Aubin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-16 19:04:22