Môže sa (a== 1 && a ==2 && a==3) niekedy vyhodnotiť ako true?

Poznámka moderátora: Odolajte, prosím, nutkaniu upraviť kód alebo odstrániť toto upozornenie. Vzor bielych znakov môže byť súčasťou otázky, a preto by sa do neho nemalo zbytočne zasahovať. Ak patríte do tábora "biele znaky sú nepodstatné", mali by ste byť schopní akceptovať kód tak, ako je.

Je vôbec možné, aby sa (a== 1 && a ==2 && a==3) mohlo vyhodnotiť ako pravdivé v jazyku JavaScript?

Túto otázku na pohovore položila jedna z veľkých technologických spoločností. Stalo sa to pred dvoma týždňami, ale stále sa snažím nájsť odpoveď. Viem, že v každodennej práci takýto kód nikdy nepíšeme, ale som zvedavý.

Riešenie

Ak využijete výhody ako funguje ==, môžete jednoducho vytvoriť objekt s vlastnou funkciou toString (alebo valueOf), ktorá pri každom použití zmení to, čo vráti, tak, aby spĺňala všetky tri podmienky.

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

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

Dôvodom, prečo to funguje, je použitie voľného operátora rovnosti. Pri použití voľnej rovnosti, ak je jeden z operandov iného typu ako druhý, motor sa pokúsi previesť jeden na druhý. V prípade objektu na ľavej strane a čísla na pravej strane sa pokúsi previesť objekt na číslo tak, že najprv zavolá operátor valueOf, ak je volateľný, a ak nie, zavolá operátor toString. V tomto prípade som použil toString jednoducho preto, že ma to napadlo, valueOf by dávalo väčší zmysel. Ak by som namiesto toho vrátil reťazec z toString, motor by sa potom pokúsil previesť reťazec na číslo, čím by sme získali rovnaký konečný výsledok, hoci s trochu dlhšou cestou.

Komentáre (19)

JE TO MOŽNÉ!

var i = 0;

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

Toto používa getter vnútri príkazu with, aby sa a vyhodnotilo na tri rôzne hodnoty.

... to však ešte neznamená, že by sa to malo používať v skutočnom kóde...

Ešte horšie je, že tento trik bude fungovať aj pri použití ===.

  var i = 0;

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

V globálnom rozsahu sa to dá dosiahnuť pomocou nasledujúcich príkazov. Pre nodejs použite v nasledujúcom kóde namiesto window global.

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

Táto odpoveď zneužíva implicitné premenné poskytované globálnym rozsahom v kontexte vykonávania definovaním gettera na získanie premennej.

Komentáre (6)