Catatan Moderator: Harap tahan keinginan untuk mengedit kode atau menghapus pemberitahuan ini. Pola spasi putih mungkin menjadi bagian dari pertanyaan dan karenanya tidak boleh dirusak dengan tidak perlu. Jika Anda berada di camp "whitespace is insignificant", Anda harus dapat menerima kode apa adanya.
Apakah mungkin (a== 1 && a ==2 && a==3)
untuk mengevaluasi true
dalam JavaScript?
Ini adalah pertanyaan wawancara yang diajukan oleh perusahaan teknologi besar. Itu terjadi dua minggu yang lalu, tetapi saya masih berusaha menemukan jawabannya. Saya tahu kami tidak pernah menulis kode seperti itu dalam pekerjaan kami sehari-hari, tetapi saya ingin tahu.
javascript
ecmascript-6
Buddha Dimpu Aravind
sumber
sumber
==
ketika Anda bermaksud===
, memiliki standar pengkodean yang melarang nama variabel non-ASCII, dan memiliki proses linting yang memberlakukan dua moral sebelumnya.Jawaban:
Jika Anda memanfaatkan cara
==
kerjanya , Anda bisa membuat objek dengan fungsi kustomtoString
(atauvalueOf
) yang mengubah apa yang dikembalikan setiap kali digunakan sehingga memenuhi ketiga kondisi.Alasan ini berhasil adalah karena penggunaan operator kesetaraan longgar. Saat menggunakan kesetaraan longgar, jika salah satu operan memiliki tipe yang berbeda dari yang lain, mesin akan berusaha untuk mengubah satu ke yang lain. Dalam hal suatu objek di sebelah kiri dan nomor di sebelah kanan, ia akan berusaha untuk mengkonversi objek ke nomor dengan terlebih dahulu memanggil
valueOf
jika itu dapat dipanggil, dan gagal itu, itu akan memanggiltoString
. Saya menggunakantoString
dalam kasus ini hanya karena itulah yang terlintas dalam pikiran,valueOf
akan lebih masuk akal. Jika saya malah mengembalikan string daritoString
, mesin kemudian akan mencoba untuk mengkonversi string ke nomor yang memberi kami hasil akhir yang sama, meskipun dengan jalur yang sedikit lebih panjang.sumber
valueOf()
operasi tersirat ?valueOf
sedikit lebih baik.i
tidak mengganggu mesin. ;)Saya tidak bisa menolak - jawaban lain tidak diragukan lagi benar, tetapi Anda benar-benar tidak dapat berjalan melewati kode berikut:
Perhatikan spasi aneh dalam
if
pernyataan (yang saya salin dari pertanyaan Anda). Ini adalah Hangul setengah lebar (itu bahasa Korea untuk mereka yang tidak terbiasa) yang merupakan karakter ruang Unicode yang tidak ditafsirkan oleh skrip ECMA sebagai karakter spasi - ini berarti bahwa itu adalah karakter yang valid untuk pengidentifikasi. 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:Periksa validasi pada validator nama variabel Mathias . Jika jarak aneh itu benar-benar dimasukkan dalam pertanyaan mereka, saya yakin itu adalah petunjuk untuk jawaban semacam ini.
Jangan lakukan ini. Serius.
Edit: Telah menjadi perhatian saya bahwa (meskipun tidak diizinkan untuk memulai variabel a) joiner Zero-lebar dan Zero-lebar non-joiner karakter juga diperkenankan dalam nama variabel - lihat Obfuscating JavaScript dengan nol-lebar karakter - pro dan kontra ?.
Ini akan terlihat seperti berikut:
sumber
var ᅠ2 = 3
telah digunakan; jadi ada tiga variabelaᅠᅠ= 1, ᅠ2 = 3, a = 3
(a␣ = 1, ␣2 = 3, a = 3
, jadi itu(a␣==1 && a==␣2 && a==3)
) ...MUNGKIN!
Ini menggunakan pengambil dalam
with
pernyataan untuk membiarkana
mengevaluasi ke tiga nilai yang berbeda.... ini masih tidak berarti ini harus digunakan dalam kode nyata ...
Lebih buruk lagi, trik ini juga akan berfungsi dengan penggunaan
===
.sumber
with
."with
tidak diizinkan.with
jadi itu bisa terjadi==
. Dan===
mencegah jawaban yang diterima==
tetapi saya belum melihatwith
sejak ... yah sebenarnya tidak pernah di luar dokumentasi JS di mana dikatakan "tolong jangan gunakan itu". Bagaimanapun, solusi yang bagus.Contoh tanpa getter atau valueOf:
Ini berfungsi karena
==
memanggiltoString
panggilan mana.join
Array.Solusi lain, menggunakan
Symbol.toPrimitive
yang setara ES6 daritoString/valueOf
:sumber
without valueOf
, well ... ini lebih tidak langsung tetapi pada dasarnya hal yang sama.toString
atauvalueOf
tetapi yang ini benar-benar mengejutkan saya. Sangat pintar dan saya tidak tahu itu memang memanggil.join
internal, tapi itu masuk akal.Jika ditanya apakah mungkin (bukan HARUS), ia dapat meminta "a" untuk mengembalikan nomor acak. Itu akan benar jika menghasilkan 1, 2, dan 3 secara berurutan.
sumber
Ketika Anda tidak dapat melakukan apa pun tanpa ekspresi reguler:
Ia bekerja karena
valueOf
metode kustom yang disebut ketika Objek dibandingkan dengan primitif (seperti Nomor). Trik utamanya adalaha.valueOf
mengembalikan nilai baru setiap kali karena memanggilexec
ekspresi reguler dengang
flag, yang menyebabkan pembaruanlastIndex
ekspresi reguler itu setiap kali ditemukan kecocokan. Jadi pertama kalinyathis.r.lastIndex == 0
, cocok1
dan updatelastIndex
:this.r.lastIndex == 1
, sehingga waktu berikutnya regex akan cocok2
dan sebagainya.sumber
exec
lagi akan mulai mencari dari indeks itu. MDN tidak begitu jelas.this.r
objek regex mengingat status / indeks. Terima kasih!exec
, bukan bilangan bulat yang harus dirubah.Hal ini dapat dicapai dengan menggunakan hal-hal berikut dalam lingkup global. Untuk
nodejs
digunakanglobal
alih-alihwindow
dalam kode di bawah ini.Jawaban ini menyalahgunakan variabel implisit yang disediakan oleh lingkup global dalam konteks eksekusi dengan mendefinisikan pengambil untuk mengambil variabel.
sumber
a
adalah propertithis
yang sepertinya tidak ada. Jikaa
variabel lokal (yang terlihat seperti), maka ini tidak akan berfungsi.a == 1
merujuk daripadaa
variabel di suatu tempat, bukan properti darithis
. Meskipun ada tempat aneh seperti global di mana keduanya bisa benar, secara umum, mendeklarasikan variabel denganvar a
ataulet a
berarti tidak adathis
yang memungkinkan Anda mengaksesa
sebagai properti seperti asumsi kode Anda. Jadi, kode Anda tampaknya mengasumsikan beberapa hal variabel global yang aneh. Misalnya, kode Anda tidak berfungsi di node.js dan tidak dalam mode ketat di dalam suatu fungsi. Anda harus menentukan keadaan di mana ia bekerja dan mungkin menjelaskan mengapa itu bekerja. Kalau tidak, itu menyesatkan.a
bukan variabel lokal dan didefinisikan pada lingkup global dengan pengambil yang bertambah.Ini dimungkinkan jika variabel
a
sedang 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 variabela
tepat pada waktunya sehingga kondisinyaa==1
,a==2
dana==3
puas.Ini bisa menjadi contoh kondisi balapan di lingkungan multi-utas yang disediakan oleh pekerja web dan SharedArrayBuffer dalam JavaScript.
Berikut ini adalah implementasi dasar di atas:
main.js
pekerja.js
modifier.js
Di MacBook Air saya, ini terjadi setelah sekitar 10 miliar iterasi pada upaya pertama:
Usaha kedua:
Seperti yang saya katakan, peluangnya akan rendah, tetapi diberikan waktu yang cukup, itu akan mengenai kondisinya.
Tip: Jika terlalu lama pada sistem Anda. Coba saja
a == 1 && a == 2
dan ubahMath.random()*3
keMath.random()*2
. Menambahkan lebih banyak dan lebih banyak lagi ke daftar akan mengurangi peluang untuk memukul.sumber
Ini juga dimungkinkan dengan menggunakan serangkaian pengambil tulisan sendiri:
(Ini mirip dengan solusi jontro, tetapi tidak memerlukan variabel counter.)
sumber
===
, bukan hanya==
.this
menjadi objek global di dalam tubuh fungsi panah.(a == 3 && a == 2 && a == 1)
,?Atau, Anda bisa menggunakan kelas untuk itu dan contoh untuk cek.
EDIT
Menggunakan kelas ES6 akan terlihat seperti ini
sumber
function A() {value = 0;
di awal?valueOf
sedang diganti,this method is usually called automatically by JavaScript behind the scenes, and not explicitly in code
jadi ketika kita membandingkan nilai itu sebenarnya menambah ..Saya tidak melihat jawaban ini sudah diposting, jadi saya akan memasukkan yang ini ke dalam campuran juga. Ini mirip dengan jawaban Jeff dengan ruang Hangul setengah lebar.
Anda mungkin melihat sedikit perbedaan dengan yang kedua, tetapi yang pertama dan ketiga identik dengan mata telanjang. Semua 3 adalah karakter yang berbeda:
a
- Huruf kecil Latin Aa
- Lebar Penuh Huruf kecil Latin Aа
- Huruf kecil Sirilik AIstilah umum untuk ini adalah "homoglyphs": karakter unicode berbeda yang terlihat sama. Biasanya sulit untuk mendapatkan tiga yang benar-benar tidak dapat dibedakan, tetapi dalam beberapa kasus Anda bisa beruntung. A, Α, А, dan Ꭺ akan bekerja lebih baik (Latin-A, Yunani Alpha , Cyrillic-A , dan Cherokee-A masing-masing; sayangnya Yunani dan Cherokee huruf kecil terlalu berbeda dari bahasa Latin
a
:α
,ꭺ
, dan sebagainya doesn dapat membantu dengan cuplikan di atas).Ada seluruh kelas Serangan Homoglyph di luar sana, paling umum dalam nama domain palsu (mis.
wikipediа.org
(Sirilik) vswikipedia.org
(Latin)), tetapi dapat juga muncul dalam kode; biasanya disebut sebagai curang (seperti yang disebutkan dalam komentar, pertanyaan [licik] sekarang di luar topik di PPCG , tetapi dulu merupakan jenis tantangan di mana hal-hal semacam ini akan muncul). Saya menggunakan situs web ini untuk menemukan homoglyph yang digunakan untuk jawaban ini.sumber
a
:a︀
a︁
a︂
. Tidak ada lagi kekhawatiran tentang perbedaan.Ya itu mungkin! 😎
»JavaScript
Kode di atas adalah versi singkat (terima kasih kepada @Forivin untuk catatannya di komentar) dan kode berikut ini asli:
» C #
Saya juga menulis versi C # ( dengan teknik peningkatan nilai properti ):
Demo Langsung
sumber
if=()=>!0
document.write
? Cara yang pasti untuk tidak dipekerjakan terlepas dari sisa jawabannya.console.log
tetapi saya mengubahnya menjadi document.write. Benar-benar selalu saya gunakanconsole.log
dalam kode saya tetapi di sini saya hanya ingin menunjukkan teks kepada pengguna di kotak snipet kode StackOverflow. Jadi saya ingin menunjukkan pesan saya lebih indah dari pesan yang dihasilkan olehconsole.log
. KlikRun Code Snippet
tombol pada jawaban saya dan pada jawaban lain. Cuplikan Kode SO memungkinkan saya untuk menggunakan html dan JS dan CSS lalu saya ingin menggunakannya dalam jawaban saya dan menjadikannya menyenangkan. Saya pikir itu tidak memiliki efek samping negatif dan tidak membuat jawaban saya besar atau puas.JavaScript
a == a +1
Dalam JavaScript, tidak ada bilangan bulat tetapi hanya
Number
s, yang diimplementasikan sebagai angka floating point presisi ganda.Ini berarti bahwa jika suatu Angka
a
cukup besar, itu dapat dianggap sama dengan tiga bilangan bulat berturut-turut:Benar, itu tidak persis apa yang diminta pewawancara (tidak bekerja dengan baik
a=0
), tetapi tidak melibatkan trik dengan fungsi tersembunyi atau kelebihan operator.Bahasa lainnya
Untuk referensi, ada
a==1 && a==2 && a==3
solusi di Ruby dan Python. Dengan sedikit modifikasi, itu juga mungkin di Jawa.Rubi
Dengan kebiasaan
==
:Atau peningkatan
a
:Python
Jawa
Dimungkinkan untuk memodifikasi
Integer
cache Java :sumber
Integer a = 42
(atau melakukannya)? Seperti yang saya mengerti autoboxing,Integer a = 42; a == 1 && a == 2 && a == 3
harus mengotak semua int. Atau apakah ini unbox a untuk perbandingan?Integer == int
sepertinya menghasilkan unboxing. Tetapi menggunakanInteger#equals(int)
kekuatan autoboxing, jadi itu berhasil. Terima kasih atas komentarnya!Numbers
di JS, yang pada dasarnya sepertidouble
s. Mereka bisa terlihat seperti bilangan bulat dan Anda bisa menggunakannya seperti bilangan bulat, tetapi mereka masih bukan bilangan bulat. Saya pikir tidakn == n + 1
pernah benar untuk bilangan bulat di Java / Python / C / Ruby / ...Ini adalah versi terbalik dari jawaban @ Jeff * di mana karakter tersembunyi (U + 115F, U + 1160 atau U + 3164) digunakan untuk membuat variabel yang terlihat seperti
1
,2
dan3
.* Jawaban itu dapat disederhanakan dengan menggunakan nol lebar non-joiner (U + 200C) dan nol lebar joiner (U + 200D). Kedua karakter ini diizinkan di dalam pengidentifikasi tetapi tidak di awal:
Trik lain dimungkinkan menggunakan ide yang sama misalnya dengan menggunakan pemilih variasi Unicode untuk membuat variabel yang persis sama (
a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true
).sumber
Peraturan nomor satu wawancara; tidak pernah mengatakan tidak mungkin.
Tidak perlu tipuan karakter tersembunyi.
sumber
__defineGetter__
sebenarnya bukan bagian dari bahasa js, hanya versi jelek daridefineProperty
.typeof
bukan fungsi dan ini dideklarasikani
hanya mengerikan. Masih tampaknya bernilai 40 upvotes: /__defineGetter__
tidak berlaku lagi per developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… tapi itu jelas dieksekusi di FireFox v 57.0.4 saya jadi saya memilih untuk menunjukkan ini daripadadefineProperty()
karena kode lama adalah nyata dan tidak dapat diabaikan. Terlepas dari keburukan, menyatakani
dalam cara saya lakukan adalah perilaku yang dikenal / didokumentasikan. Mungkin aku sedang dalam mood PCG ¯ \ _ (ツ) _ / ¯Jujur saja, apakah ada cara untuk mengevaluasi ke benar atau tidak (dan seperti yang telah ditunjukkan orang lain, ada beberapa cara), jawaban yang saya cari, berbicara sebagai seseorang yang telah melakukan ratusan wawancara, akan menjadi sesuatu di sepanjang baris:
"Yah, mungkin ya dalam beberapa keadaan aneh yang tidak segera jelas bagi saya ... tetapi jika saya menemukan ini dalam kode nyata maka saya akan menggunakan teknik debugging umum untuk mencari tahu bagaimana dan mengapa ia melakukan apa yang dilakukannya dan kemudian segera refactor kode untuk menghindari situasi itu ... tetapi yang lebih penting: Saya benar-benar TIDAK akan pernah menulis kode itu di tempat pertama karena itu adalah definisi dari kode yang berbelit-belit, dan saya berusaha untuk tidak pernah menulis kode yang berbelit-belit ".
Saya kira beberapa pewawancara akan tersinggung untuk memiliki apa yang jelas-jelas dimaksudkan sebagai pertanyaan yang sangat rumit, tetapi saya tidak keberatan pengembang yang memiliki pendapat, terutama ketika mereka dapat mendukungnya dengan pemikiran yang masuk akal dan dapat menyelaraskan pertanyaan saya menjadi pernyataan yang bermakna tentang diri mereka sendiri.
sumber
Jika Anda pernah mendapatkan pertanyaan wawancara semacam itu (atau perhatikan beberapa perilaku yang sama sekali tidak terduga dalam kode Anda) pikirkan tentang hal-hal apa yang dapat menyebabkan perilaku yang terlihat mustahil pada pandangan pertama:
Pengkodean : Dalam hal ini variabel yang Anda lihat bukan yang Anda pikirkan. Ini bisa terjadi jika Anda sengaja dipusingkan dengan Unicode menggunakan homoglyphs atau karakter spasi untuk membuat nama variabel terlihat seperti yang lain, tetapi masalah penyandian juga dapat diperkenalkan secara tidak sengaja, misalnya saat menyalin & menempelkan kode dari Web yang berisi kode Unicode yang tidak terduga poin (misalnya karena sistem manajemen konten melakukan beberapa "pemformatan otomatis" seperti mengganti
fl
dengan Unicode 'LATIN SMALL LIGATURE FL' (U + FB02)).Kondisi balapan : Suatu kondisi balapan mungkin terjadi, yaitu situasi di mana kode tidak dieksekusi dalam urutan yang diharapkan oleh pengembang. Kondisi balapan sering terjadi dalam kode multi-ulir, tetapi beberapa utas bukan merupakan persyaratan agar kondisi balapan dimungkinkan - asinkronisitas sudah cukup (dan jangan bingung, async tidak berarti beberapa utas digunakan di bawah tenda ).
Perhatikan bahwa oleh karena itu JavaScript juga tidak bebas dari kondisi balapan hanya karena itu adalah single-threaded. Lihat di sini untuk contoh single-threaded sederhana - tetapi async -. Namun dalam konteks pernyataan tunggal, kondisi balapan akan agak sulit dicapai di JavaScript.
JavaScript dengan pekerja web sedikit berbeda, karena Anda dapat memiliki banyak utas. @mehulmpt telah menunjukkan kepada kami bukti-konsep hebat menggunakan pekerja web .
Efek samping : Efek samping dari operasi perbandingan kesetaraan (yang tidak harus sejelas dalam contoh di sini, seringkali efek samping sangat halus).
Masalah-masalah semacam ini dapat muncul dalam banyak bahasa pemrograman, tidak hanya JavaScript, jadi kami tidak melihat salah satu WTF JavaScript klasik di sini 1 .
Tentu saja, pertanyaan wawancara dan sampel di sini semua terlihat sangat dibuat-buat. Tetapi mereka adalah pengingat yang baik bahwa:
1 Misalnya, Anda dapat menemukan contoh dalam bahasa pemrograman yang sama sekali berbeda (C #) yang menunjukkan efek samping (yang jelas) di sini .
sumber
Berikut variasi lain, menggunakan array untuk memunculkan nilai apa pun yang Anda inginkan.
sumber
Oke, peretasan lain dengan generator:
sumber
this
objek jendela)Menggunakan Proxy :
Proxy pada dasarnya berpura-pura menjadi objek target (parameter pertama), tetapi mencegat operasi pada objek target (dalam hal ini operasi "dapatkan properti") sehingga ada peluang untuk melakukan sesuatu selain perilaku objek default. Dalam hal ini tindakan "dapatkan properti" dipanggil
a
saat==
memaksa jenisnya untuk membandingkannya dengan setiap nomor. Ini terjadi:{ i: 0 }
,, di manai
properti adalah counter kamia
a ==
perbandingan,a
tipe dipaksa ke nilai primitifa[Symbol.toPrimitive]()
internala[Symbol.toPrimitive]
fungsi menggunakan "get handler"Symbol.toPrimitive
, dalam hal ini akan menambahkan dan kemudian mengembalikan counter dari objek target:++target.i
. Jika properti yang berbeda sedang diambil, kami hanya kembali ke mengembalikan nilai properti default,target[name]
Begitu:
Seperti sebagian besar jawaban lainnya, ini hanya berfungsi dengan pemeriksaan kesetaraan longgar (
==
), karena pemeriksaan kesetaraan yang ketat (===
) tidak melakukan paksaan yang dapat disadap oleh Proxy.sumber
Symbol.toPrimitive
dengan cara yang sama pada suatu objek akan bekerja juga.Sebenarnya jawaban untuk bagian pertama dari pertanyaan adalah "Ya" di setiap bahasa pemrograman. Sebagai contoh, ini dalam kasus C / C ++:
sumber
&&
untuk logika "dan".Sama, tetapi berbeda, tetapi tetap sama (dapat "diuji" beberapa kali):
Ide saya mulai dari bagaimana persamaan tipe objek Nomor bekerja.
sumber
Sebuah jawaban ECMAScript 6 yang memanfaatkan Simbol:
Karena
==
penggunaan, JavaScript seharusnya memaksaa
menjadi sesuatu yang dekat dengan operan kedua (1
,2
,3
dalam hal ini). Tetapi sebelum JavaScript mencoba mencari paksaan sendiri, ia mencoba meneleponSymbol.toPrimitive
. Jika Anda memberikanSymbol.toPrimitive
JavaScript akan menggunakan nilai yang dikembalikan fungsi Anda. Jika tidak, JavaScript akan memanggilvalueOf
.sumber
Saya pikir ini adalah kode minimal untuk mengimplementasikannya:
Membuat objek dummy dengan kebiasaan
valueOf
yang menambah variabel globali
pada setiap panggilan. 23 karakter!sumber
Yang ini menggunakan defineProperty dengan efek samping yang bagus yang menyebabkan variabel global!
sumber
a
:get: (a => () => ++a)(0),
tidak perlu global.Dengan mengesampingkan
valueOf
deklarasi kelas, itu dapat dilakukan:Yang terjadi adalah yang
valueOf
disebut di setiap operator perbandingan. Pada yang pertama,a
akan sama1
, pada yang kedua,a
akan sama2
, dan seterusnya dan seterusnya, karena setiap kalivalueOf
dipanggil, nilaia
bertambah.Oleh karena itu console.log akan aktif dan keluaran (di terminal saya)
Thing: { value: 4}
, menunjukkan syarat itu benar.sumber