Pertanyaan Dapatkah (a == 1 && a == 2 && a == 3) pernah mengevaluasi ke true?


Catatan moderator: Harap tahan dorongan untuk mengedit kode atau menghapus pemberitahuan ini. Pola spasi putih dapat menjadi bagian dari pertanyaan dan oleh karena itu tidak boleh dirusak dengan tidak perlu. Jika Anda berada di kamp "whitespace is signifikan", Anda harus dapat menerima kode apa adanya.

Apakah mungkin itu (a== 1 && a ==2 && a==3) bisa mengevaluasi ke true di JavaScript?

Ini adalah pertanyaan wawancara yang ditanyakan oleh perusahaan teknologi besar. Itu terjadi dua minggu lalu, tetapi saya masih berusaha mencari jawabannya. Saya tahu kita tidak pernah menulis kode seperti itu dalam pekerjaan sehari-hari, tetapi saya ingin tahu.


2250
2018-01-15 20:20


asal


Jawaban:


Jika Anda memanfaatkan bagaimana == bekerja, Anda cukup membuat objek dengan custom toString (atau valueOf) fungsi yang mengubah apa yang dikembalikan setiap kali digunakan sehingga memenuhi ketiga kondisi.

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

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


Alasan ini bekerja adalah karena penggunaan operator kesetaraan longgar. Ketika menggunakan persamaan longgar, jika salah satu operand memiliki tipe yang berbeda dari yang lain, mesin akan mencoba untuk mengkonversi satu ke yang lain. Dalam kasus objek di sebelah kiri dan nomor di sebelah kanan, itu akan mencoba untuk mengubah objek ke nomor dengan panggilan pertama valueOf jika itu bisa ditelepon, dan gagal, itu akan menelepon toString. Saya menggunakan toString dalam hal ini hanya karena itu yang terlintas dalam pikiran, valueOf akan lebih masuk akal. Jika saya mengembalikan string dari toString, mesin akan mencoba mengubah string menjadi angka yang memberi kita hasil akhir yang sama, meskipun dengan jalur yang sedikit lebih panjang.


3091
2018-01-15 20:35



Saya tidak bisa menolak - jawaban yang lain tidak diragukan lagi benar, tetapi Anda benar-benar tidak dapat melewati kode berikut:

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

Perhatikan jarak yang aneh di if pernyataan (yang saya salin dari pertanyaan Anda). Ini adalah Hangul setengah lebar (itu Korea bagi mereka yang tidak akrab) yang merupakan karakter ruang Unicode yang tidak ditafsirkan oleh skrip ECMA sebagai karakter ruang - ini berarti bahwa itu adalah karakter yang valid untuk identifier. Oleh karena itu ada tiga variabel yang sangat berbeda, satu dengan Hangul setelah a, satu dengan sebelumnya dan yang terakhir hanya dengan a. Mengganti ruang dengan _ untuk keterbacaan, kode yang sama akan terlihat seperti ini:

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

Periksa validasi pada validator nama variabel Mathias. Jika jarak aneh itu benar-benar dimasukkan dalam pertanyaan mereka, saya merasa yakin itu adalah petunjuk untuk jawaban semacam ini.

Jangan lakukan ini. Serius

Edit: Ini telah menjadi perhatian saya bahwa (meskipun tidak diizinkan untuk memulai suatu variabel) Zero-width joiner dan Zero-width non-joiner karakter juga diizinkan dalam nama variabel - lihat Mengaburkan JavaScript dengan karakter lebar-nol - pro dan kontra?.

Ini akan terlihat seperti berikut:

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


1914
2018-01-16 05:14



ITU MUNGKIN!

var i = 0;

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

Ini menggunakan pengambil di dalam with pernyataan untuk dibiarkan a mengevaluasi ke tiga nilai yang berbeda.

... ini tetap tidak berarti ini harus digunakan dalam kode nyata ...


565
2018-01-15 20:35



Contoh tanpa getter atau valueOf:

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

Ini berfungsi karena == meminta toString panggilan mana .join untuk Array.

Solusi lain, menggunakan Symbol.toPrimitive yang setara dengan ES6 toString/valueOf:

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

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


428
2018-01-17 11:37



Jika ditanya apakah mungkin (tidak HARUS), dapat meminta "a" untuk mengembalikan nomor acak. Akan benar jika menghasilkan 1, 2, dan 3 secara berurutan.

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;
    }
  }
}


249
2018-01-16 06:21



Ketika Anda tidak dapat melakukan apa pun tanpa ekspresi reguler:

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

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

Berhasil karena kebiasaan valueOf metode yang disebut ketika Obyek dibandingkan dengan primitif (seperti Nomor). Trik utamanya adalah itu a.valueOf mengembalikan nilai baru setiap kali karena panggilannya exec pada ekspresi reguler dengan g bendera, yang menyebabkan pembaruan lastIndex dari ekspresi reguler setiap kali kecocokan ditemukan. Jadi pertama kali this.r.lastIndex == 0, itu cocok 1 dan pembaruan lastIndex: this.r.lastIndex == 1, sehingga waktu berikutnya regex akan cocok 2 dan seterusnya.


195
2018-01-16 19:35



Ini dapat dicapai dengan menggunakan hal-hal berikut dalam lingkup global. Untuk nodejs menggunakan global dari pada window dalam kode di bawah ini.

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

Jawaban ini menyalahgunakan variabel implisit yang disediakan oleh lingkup global dalam konteks eksekusi dengan mendefinisikan pengambil untuk mengambil variabel.


183
2018-01-15 20:37



Ini mungkin dalam kasus variabel a diakses oleh, katakanlah 2 pekerja web melalui SharedArrayBuffer serta beberapa skrip utama. Kemungkinannya rendah, tetapi ada kemungkinan bahwa ketika kode dikompilasi ke kode mesin, pekerja web memperbarui variabel a tepat pada waktunya begitu kondisinya a==1, a==2 dan a==3 puas.

Ini bisa menjadi contoh kondisi balapan di lingkungan multi-threaded yang disediakan oleh pekerja web dan SharedArrayBuffer di JavaScript.

Berikut adalah implementasi dasar di atas:

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

Di MacBook Air saya, itu terjadi setelah sekitar 10 miliar iterasi pada upaya pertama:

enter image description here

Usaha kedua:

enter image description here

Seperti yang saya katakan, kemungkinannya akan rendah, tetapi dengan waktu yang cukup, itu akan memukul kondisi.

Kiat: Jika terlalu lama di sistem Anda. Coba saja a == 1 && a == 2 dan berubah Math.random()*3 untuk Math.random()*2. Menambahkan lebih banyak dan lebih banyak untuk daftar menjatuhkan kemungkinan memukul.


171
2018-01-17 07:39