Dapat (a== 1 && a ==2 && a==3) pernah mengevaluasi dengan benar?
Moderator note: Jangan menahan keinginan untuk mengedit kode atau menghapus pemberitahuan ini. Pola spasi dapat menjadi bagian dari pertanyaan dan oleh karena itu tidak boleh dirusak dengan yang tidak perlu. Jika anda berada di "spasi adalah signifikan," kamp, anda harus dapat menerima kode tersebut.
Itu pernah mungkin bahwa (a== 1 && a ==2 && a==3)
bisa mengevaluasi untuk benar
di JavaScript?
Ini adalah pertanyaan wawancara yang diajukan oleh perusahaan teknologi besar. Itu terjadi dua minggu lalu, tapi saya'm masih berusaha untuk menemukan jawabannya. Aku tahu kita tidak pernah menulis kode tersebut di hari-hari kerja, tapi saya'm penasaran.
2440
26
Jika anda mengambil keuntungan dari cara
==
worksanda hanya bisa membuat objek dengan customtoString
(atauvalueOf
) fungsi yang mengubah apa itu kembali setiap kali digunakan sedemikian rupa sehingga memenuhi semua tiga kondisi.Alasan ini bekerja adalah karena penggunaan longgar kesetaraan operator. Ketika menggunakan longgar kesetaraan, jika salah satu operand adalah dari tipe yang berbeda dari yang lain, mesin akan mencoba untuk mengkonversi satu ke yang lain. Dalam kasus sebuah objek di kiri dan di kanan, itu akan mencoba untuk mengkonversi objek ke nomor dengan terlebih dahulu memanggil
valueOf
jika itu adalah callable, dan gagal itu, ia akan memanggiltoString
. Saya menggunakantoString
dalam hal ini hanya karena itu's apa yang datang ke pikiran,valueOf
akan membuat lebih masuk akal. Kalau aku malah kembali string daritoString
, mesin akan kemudian mencoba untuk mengkonversi string ke number memberikan hasil akhir yang sama, meskipun dengan jalan yang sedikit lebih lama.Saya tidak't resist - lain jawaban yang pasti benar, tapi anda benar-benar dapat't berjalan melewati kode berikut:
Catatan aneh spasi di
jika
pernyataan (yang saya disalin dari pertanyaan anda). Itu adalah setengah lebar Hangul (yang's korea bagi mereka yang tidak akrab) yang merupakan Unicode karakter spasi yang tidak ditafsirkan oleh ECMA script seperti karakter ruang - ini berarti bahwa ia adalah karakter yang valid untuk identifier. Oleh karena itu ada tiga benar-benar variabel yang berbeda, satu dengan Hangul setelah a, satu dengan sebelumnya dan yang terakhir dengan hanya. Mengganti ruang dengan_
untuk dibaca, kode yang sama akan terlihat seperti ini:Check out validasi pada Mathias' nama variabel validator. Jika yang aneh jarak sebenarnya termasuk dalam pertanyaan mereka, saya merasa yakin bahwa itu's petunjuk untuk jenis jawaban.
Don't melakukan hal ini. Serius.
Edit: Itu telah datang ke perhatian saya yang (meskipun tidak diizinkan untuk memulai variabel) yang Nol-lebar joiner dan Zero width non-joiner karakter juga diizinkan dalam nama-nama variabel - lihat Obfuscating JavaScript dengan nol-lebar karakter - pro dan kontra?.
Ini akan terlihat seperti berikut:
HAL INI MUNGKIN!
Ini menggunakan getter dalam
dengan
pernyataan untuk membiarkana
untuk mengevaluasi tiga nilai yang berbeda.... ini masih tidak berarti ini harus digunakan dalam kode nyata...
Bahkan lebih buruk lagi, trik ini juga akan bekerja dengan menggunakan
===
.Contoh tanpa getter atau valueOf:
Ini bekerja karena
==
memanggiltoString
panggilan.join
untuk Array.Solusi lain, menggunakan
Simbol.toPrimitive
yang merupakan ES6 setara dengantoString/valueOf
:Jika ditanya apakah mungkin (tidak HARUS), dapat bertanya "a" untuk kembali nomor acak. Itu akan menjadi benar jika itu menghasilkan 1, 2, dan 3 secara berurutan.
Ketika anda dapat't melakukan apa-apa tanpa ekspresi reguler:
Ia bekerja karena custom
valueOf
metode yang dipanggil saat Objek dibandingkan dengan primitif (seperti Nomor). Trik utama adalah bahwa.valueOf
mengembalikan nilai baru setiap saat karena itu's callingexec
pada ekspresi reguler dengang
bendera, yang menyebabkan memperbaruilastIndex
bahwa ekspresi reguler setiap kali pertandingan ditemukan. Jadi dulu waktuini.r.lastIndex == 0
, ini pertandingan1
dan updatelastIndex
:ini.r.lastIndex == 1
, sehingga waktu berikutnya regex akan match2
dan seterusnya.Ini adalah mungkin dalam kasus variabel
a
yang diakses oleh, katakanlah 2 pekerja web melalui SharedArrayBuffer serta beberapa naskah utama. Kemungkinan lebih rendah, tetapi adalah mungkin bahwa ketika kode ini disusun untuk kode mesin, pekerja web memperbarui variabela
tepat pada waktunya sehingga kondisia==1
,a==2
dana==3
puas.Ini dapat menjadi contoh dari kondisi balapan di multi-threaded lingkungan yang disediakan oleh web pekerja dan SharedArrayBuffer dalam JavaScript.
Berikut ini adalah dasar pelaksanaan atas:
main.js
worker.js
modifier.js
Pada MacBook Air, hal itu terjadi setelah sekitar 10 miliar iterasi pada upaya pertama:
Upaya kedua:
Seperti yang saya katakan, kemungkinan akan rendah, tetapi mengingat waktu yang cukup, it'll memukul kondisi.
Tip: Jika waktu terlalu lama pada sistem anda. Cobalah hanya
a == 1 && a == 2
dan ubahMatematika.random()*3
untukMatematika.random()*2
. Menambahkan lebih banyak dan lebih banyak untuk daftar tetes kesempatan memukul.Hal ini dapat dicapai dengan menggunakan kode berikut dalam lingkup global. Untuk
nodejs
menggunakanglobal
dan bukanjendela
di dalam kode di bawah ini.Jawaban ini pelanggaran implisit variabel yang disediakan oleh lingkup global dalam konteks eksekusi dengan mendefinisikan getter untuk mengambil nilai variabel.
Ini juga mungkin menggunakan serangkaian self-timpa getter:
(Hal ini mirip dengan jontro's solusi, tapi doesn't memerlukan variabel counter.)
Sebagai alternatif, anda bisa menggunakan class dan instance untuk memeriksa.
function A() { var nilai = 0; ini.valueOf = function () { return ++value; }; }
EDIT
Menggunakan ES6 kelas itu akan terlihat seperti ini
Saya don't melihat jawaban ini sudah diposting, jadi saya'll membuang yang satu ini ke dalam campuran juga. Hal ini mirip dengan Jeff's jawaban dengan setengah-lebar Hangul ruang.
Anda mungkin melihat sedikit perbedaan dengan yang kedua, tapi yang pertama dan ketiga adalah identik dengan mata telanjang. Semua 3 karakter yang berbeda:
a
- Latin huruf Aa
- Lebar Penuh Latin huruf Aа
- Huruf huruf AIstilah umum untuk ini adalah "homoglyphs": berbeda karakter unicode yang terlihat sama. Biasanya sulit untuk mendapatkan tiga bahwa benar-benar tidak bisa dibedakan, tetapi dalam beberapa kasus, anda bisa mendapatkan beruntung. A, Α, А, dan Ꭺ akan bekerja lebih baik (Latin-A, yunani Alpha, Huruf-A, dan Cherokee-A masing-masing; sayangnya yunani dan Cherokee huruf yang terlalu berbeda dari bahasa Latin
a
:α
,ꭺ
, dan jadi doesn't membantu dengan potongan di atas).Ada's seluruh kelas Homoglyph Serangan di luar sana, paling sering di palsu nama domain (misalnya.
wikipedia.org
(Cyrillic) vswikipedia.org
(Latin)), tetapi dapat muncul di kode juga; biasanya disebut sebagai licik (seperti yang disebutkan dalam komentar, [curang] pertanyaan sekarang off-topik di PPCG, tapi digunakan untuk menjadi jenis tantangan di mana hal-hal semacam ini akan muncul). Aku digunakan website untuk menemukan homoglyphs digunakan untuk jawaban ini.Ya, itu mungkin! 😎
» JavaScript
Kode di atas adalah versi pendek (terima kasih untuk @Forivin untuk dicatat dalam komentar) dan berikut kode asli:
» C#
Saya juga menulis sebuah C# version (dengan meningkatkan nilai properti technic):
Live Demo
JavaScript
a == a +1
Dalam JavaScript, tidak ada [bulat], 1 tetapi hanya `Nomor ini, yang dilaksanakan sebagai double precision floating point nomor.
Itu berarti bahwa jika Nomor
a
yang cukup besar, hal ini dapat dianggap sama dengan tiga berturut-turut bilangan bulat:Benar, itu's tidak persis apa yang pewawancara bertanya (itu doesn't bekerja dengan
a=0
), tapi itu doesn't melibatkan trik tersembunyi dengan fungsi atau operator overloading.Bahasa lain
Untuk referensi, ada
a==1 && a==2 && a==3
solusi Ruby dan Python. Dengan sedikit modifikasi, it's juga mungkin di pulau Jawa.Ruby
Dengan custom
==
:Atau peningkatan
a
:Python
Java
It's mungkin untuk memodifikasi Jawa
bilangan Bulat
cache:Ini adalah terbalik versi @Jeff's jawaban* di mana karakter tersembunyi (U+115F, U+1160 atau U+3164) digunakan untuk membuat variabel-variabel yang terlihat seperti
1
,2
dan3
.* Jawaban itu dapat disederhanakan dengan menggunakan zero width non-joiner (U+200C) dan lebar nol joiner (U+200D). Kedua karakter ini diperbolehkan dalam pengidentifikasi tapi tidak di awal:
Trik lain yang mungkin menggunakan ide yang sama misalnya dengan menggunakan Unicode variasi penyeleksi untuk membuat variabel-variabel yang terlihat persis sama (
a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true
).Aturan nomor satu dari wawancara; tidak pernah mengatakan tidak mungkin.
Tidak perlu untuk karakter tersembunyi tipu daya.
Jujur saja, apakah ada cara untuk itu untuk mengevaluasi dengan benar atau tidak (dan lain-lain telah menunjukkan, ada beberapa cara), jawaban saya'a akan mencari, berbicara sebagai seseorang yang telah melakukan ratusan wawancara, akan menjadi sesuatu di sepanjang baris:
"Yah, mungkin ya di bawah beberapa set aneh dari keadaan yang tidak't segera jelas bagi saya... tapi jika saya mengalami ini di kode nyata maka saya akan menggunakan umum debugging teknik untuk mencari tahu bagaimana dan mengapa itu melakukan apa yang dilakukannya dan kemudian segera refactor kode untuk menghindari situasi itu... tapi yang lebih penting: saya akan benar-benar PERNAH menulis kode itu di tempat pertama karena itu adalah definisi yang sangat berbelit-belit kode, dan saya berusaha untuk tidak pernah menulis berbelit-belit kode".
Saya kira beberapa pewawancara akan tersinggung untuk memiliki apa yang jelas dimaksudkan untuk menjadi sebuah pertanyaan yang sangat rumit yang disebut keluar, tapi aku don't pikiran pengembang yang memiliki pendapat, terutama ketika mereka bisa kembali ke atas dengan beralasan berpikir dan pas saya pertanyaan menjadi pernyataan yang berarti tentang diri mereka sendiri.
Jika anda pernah mendapatkan sebuah pertanyaan wawancara (atau sama-sama melihat beberapa perilaku tak terduga dalam kode anda) berpikir tentang apa jenis hal-hal yang bisa menyebabkan perilaku yang tampak mustahil pada pandangan pertama:
Encoding: Dalam hal ini variabel yang anda cari di bukan salah satu yang anda pikir itu adalah. Hal ini dapat terjadi jika anda sengaja main-main dengan Unicode menggunakan homoglyphs atau space karakter untuk membuat nama variabel yang terlihat seperti satu sama lain, tapi masalah pengkodean juga dapat diperkenalkan secara tidak sengaja, misalnya ketika menyalin & paste kode dari Web yang berisi terduga kode Unicode poin (misalnya karena sistem manajemen konten melakukan beberapa "auto-format" seperti mengganti
fl
dengan Unicode 'KECIL LATIN LIGATUR FL' (U+FB02)).Kondisi ras: A race-kondisi mungkin terjadi, yaitu situasi di mana kode ini tidak mengeksekusi dalam urutan yang diharapkan oleh pengembang. Perlombaan kondisi yang sering terjadi pada multi-threaded kode, tapi beberapa thread yang tidak merupakan persyaratan untuk kondisi balapan menjadi mungkin – asynchronicity cukup (dan don't bingung, async tidak berarti beberapa benang yang digunakan di bawah hood).
Perhatikan bahwa oleh karena itu JavaScript ini juga tidak lepas dari kondisi balapan hanya karena itu adalah single-threaded. Lihat di sini untuk sederhana single-threaded – tapi async – contoh. Dalam konteks pernyataan tunggal dengan kondisi balapan namun akan menjadi lebih sulit untuk memukul di JavaScript.
JavaScript dengan pekerja web ini sedikit berbeda, karena anda dapat memiliki beberapa benang. @mehulmpt telah menunjukkan kepada kita besar bukti-of-konsep menggunakan pekerja web.
Jenis-jenis masalah yang dapat muncul di banyak bahasa pemrograman, tidak hanya JavaScript, sehingga kita tidak't melihat salah satu klasik JavaScript WTFs di sini1.
Tentu saja, pertanyaan wawancara dan sampel di sini semua terlihat sangat dibuat-buat. Tapi mereka adalah pengingat yang baik bahwa:
1 misalnya, anda dapat menemukan contoh yang benar-benar berbeda bahasa pemrograman (C#) menunjukkan efek samping (salah satu yang jelas) di sini.
Berikut ini's variasi lain, dengan menggunakan array untuk pop dari apapun nilai-nilai yang anda inginkan.
Oke, hack lain dengan generator:
Menggunakan Proxy:
Proxy pada dasarnya berpura-pura menjadi target objek (parameter pertama), tapi mencegat operasi pada objek target (dalam hal ini "mendapatkan properti" operasi) sehingga ada kesempatan untuk melakukan sesuatu yang lain dari yang default objek perilaku. Dalam kasus ini, "mendapatkan properti" tindakan ini disebut
a
ketika==
memaksa jenisnya dalam rangka untuk membandingkannya dengan masing-masing nomor. Hal ini terjadi:{ i: 0 }
, manaaku
properti counter kamia
a ==
perbandingan,a
's jenis dipaksa untuk primitif nilaia[Simbol.toPrimitive]()
secara internala[Simbol.toPrimitive]
fungsi menggunakan "mendapatkan handler"Simbol.toPrimitive
, dalam hal ini penambahan dan kemudian kembali counter dari objek target:++target.aku
. Jika sebuah properti yang berbeda yang diambil, kita hanya jatuh kembali untuk kembali properti nilai default,target[nama]
Jadi:
Seperti dengan sebagian besar jawaban yang lain, ini hanya bekerja dengan longgar cek kesetaraan (
==
), karena yang ketat kesetaraan cek (===
) tidak melakukan jenis paksaan bahwa Proxy dapat mencegat.