Bisakah (a == 1 && a == 2 && a == 3) pernah dievaluasi menjadi true?

2484

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 truedalam 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.

Buddha Dimpu Aravind
sumber
9
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
tipuan
109
Bagi orang-orang yang tampaknya memilih cloae ini terlalu luas : apakah itu penggalian di Javascript, mengatakan bahwa ada terlalu banyak jawaban yang valid?
mulai
24
Beberapa orang duduk berfilosofi tentang apa yang mungkin. Yang lain memfokuskan upaya mereka pada apakah mereka membangun produk yang layak, bisnis yang benar untuk klien mereka. IMO, pertanyaan ini tidak memiliki kegunaan praktis di luar kenyataan bahwa Anda seharusnya tidak pernah menanyakan pertanyaan semacam ini dalam wawancara atau menulis kode semacam ini. Itu sebabnya harus ditutup. Maksud saya sungguh, apakah bisnis menyadari mereka membayar seseorang uang nyata untuk duduk-duduk dan membicarakan hal ini?
P.Brian.Mackey
15
Setelah membaca jawaban, moral dari cerita ini adalah: jangan gunakan ==ketika Anda bermaksud ===, memiliki standar pengkodean yang melarang nama variabel non-ASCII, dan memiliki proses linting yang memberlakukan dua moral sebelumnya.
Jesse C. Slicer
87
Catatan Moderator: Stack Overflow telah memiliki riwayat orang yang berbincang dengan jawaban dalam bahasa yang berbeda dengan yang dipertanyakan. Ini adalah upaya untuk menjawab pertanyaan karena mereka adalah solusi untuk masalah umum, meskipun dalam bahasa yang berbeda. Harap jangan menandainya sebagai "bukan jawaban". Karena itu, tolong jangan menahan diri untuk mengirim lebih banyak jawaban dalam berbagai bahasa - ada alasan pertanyaan ini khusus untuk JavaScript, seperti yang ditunjukkan oleh komentar di bawah beberapa jawaban lain ini, dan ada alasan kami menyukai pertanyaan khusus bahasa kami untuk tetap demikian.
BoltClock

Jawaban:

3323

Jika Anda memanfaatkan cara ==kerjanya , Anda bisa membuat objek dengan fungsi kustom toString(atau valueOf) 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 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 valueOfjika itu dapat dipanggil, dan gagal itu, itu akan memanggil toString. Saya menggunakantoString dalam kasus ini hanya karena itulah yang terlintas dalam pikiran, valueOfakan lebih masuk akal. Jika saya malah mengembalikan string dari toString, mesin kemudian akan mencoba untuk mengkonversi string ke nomor yang memberi kami hasil akhir yang sama, meskipun dengan jalur yang sedikit lebih panjang.

Kevin B
sumber
70
Bisakah Anda mencapai ini dengan mengubah valueOf()operasi tersirat ?
Sterling Archer
43
Ya, valueOf berfungsi menggantikan toString karena alasan yang sama
Kevin B
4
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
tipuan
13
Menurut ini konversi nomor akan dicoba terlebih dahulu sehingga valueOfsedikit lebih baik.
Salman A
6
@ Pureferret sisi kiri perbandingan kesetaraan adalah sebuah objek, bukan angka. Objek yang memiliki properti nomor itidak mengganggu mesin. ;)
tommeding
2057

Saya tidak bisa menolak - jawaban lain tidak diragukan lagi benar, tetapi Anda benar-benar tidak dapat berjalan 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 spasi aneh dalam ifpernyataan (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:

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 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:

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

Jeff
sumber
368
Menilai oleh jarak aneh dalam pertanyaan awal, saya pikir ini PERSIS jawaban yang dicari oleh pertanyaan wawancara - mengeksploitasi karakter non-spasi yang terlihat seperti spasi. Tempat yang bagus!
Baracus
18
@Baracus Adalah RonJohn yang memperhatikan jarak aneh dalam komentarnya pada jawaban Kevin yang mengingatkan saya pada teknik (mengerikan) ini, jadi saya tidak bisa mengambil kredit untuk melihatnya. Saya agak terkejut tidak ada yang menjawab dengan ini, karena pekerjaan saya terjadi beberapa tahun yang lalu karena posting blog di suatu tempat - saya agak berasumsi itu sudah menjadi pengetahuan umum sekarang.
Jeff
102
Tentu saja, ini dilarang sebagai celah standar , yang juga berlaku untuk wawancara. [rujukan?]
Sanchises
13
Mempertimbangkan spasi asli, mungkin bahkan lebih buruk, yaitu variabel var ᅠ2 = 3telah digunakan; jadi ada tiga variabel aᅠᅠ= 1, ᅠ2 = 3, a = 3( a␣ = 1, ␣2 = 3, a = 3, jadi itu (a␣==1 && a==␣2 && a==3)) ...
Holger
2
@ AL-zami ada karakter tambahan dalam dua variabel, yang ditampilkan di layar Anda sebagai spasi, tetapi ditafsirkan sebagai bagian dari pengenal, artinya ada tiga variabel terpisah - a, a dan a - karakter tambahan adalah ruang Hangul setengah lebar.
Jeff
620

MUNGKIN!

var i = 0;

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

Ini menggunakan pengambil dalam withpernyataan 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 ===.

  var i = 0;

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

Jonas Wilms
sumber
65
Ya saya mencoba hal yang sama :) Jadi jawaban yang benar dalam wawancara itu adalah, "Itu tidak bisa terjadi dalam kode saya karena saya tidak pernah menggunakan with."
Runcing
7
@Pointy - Dan, saya memprogram dalam mode ketat di mana withtidak diizinkan.
jfriend00
6
@Pointy dalam jawaban yang diterima mereka melakukan sesuatu yang serupa tanpa withjadi itu bisa terjadi
Jungkook
2
@ jorrit tidak ada yang akan menggunakan ==. Dan ===mencegah jawaban yang diterima
Jonas Wilms
4
@JonasW. Banyak orang masih menggunakan ==tetapi saya belum melihat withsejak ... yah sebenarnya tidak pernah di luar dokumentasi JS di mana dikatakan "tolong jangan gunakan itu". Bagaimanapun, solusi yang bagus.
Perjalanan
516

Contoh tanpa getter atau valueOf:

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

Ini berfungsi karena ==memanggiltoString panggilan mana.join Array.

Solusi lain, menggunakan Symbol.toPrimitiveyang setara ES6 dari toString/valueOf:

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

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

georg
sumber
9
without valueOf, well ... ini lebih tidak langsung tetapi pada dasarnya hal yang sama.
Jonas Wilms
11
Saya sangat menyukai solusi ini karena Anda tidak menimpa apa pun selain objek yang memiliki fungsi gabung, dan ini hanya retasan yang sangat bersih dan mudah dibaca yang membuat logika dievaluasi menjadi benar.
Alex Pedersen
28
Jujur saya pikir ini adalah jawaban terbaik. Ini tidak melibatkan sesuatu yang luar biasa, hanya menetapkan beberapa nilai. Sangat mudah dimengerti bahkan dengan pengetahuan JS dasar. Sudah selesai dilakukan dengan baik.
Zac Delventhal
14
Ini sangat masuk akal sehingga hampir terasa bermanfaat.
Andrew
7
Saya tahu sebagian besar jawaban akan tentang pelecehan toStringatau valueOftetapi yang ini benar-benar mengejutkan saya. Sangat pintar dan saya tidak tahu itu memang memanggil .joininternal, tapi itu masuk akal.
GBarroso
268

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.

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

ocomfd
sumber
102
Saya akan dengan sengaja memberikan jawaban ini bahkan jika saya tahu solusi lain, karena itu menjawab pertanyaan tetapi jelas bukan apa yang mereka cari. Mainkan game bodoh, menangkan hadiah bodoh.
ESR
2
Tetapi bagaimana jika dibutuhkan lebih dari 1000 percobaan?
Piyin
9
@Piyin Jika butuh lebih dari 1000 uji coba, Anda memenangkan hadiah!
Skeets
5
Saya suka jawaban ini karena membawanya ke ekstrem menunjukkan bahwa ini mungkin dalam bahasa apa pun jika register / cache cpu terkena dengan sinar kosmik yang cukup ketika program sedang berjalan, atau jika seseorang sengaja melakukan kesalahan daya sehingga cabang kegagalan dari jika kondisional tidak benar-benar melompat.
Ponkadoodle
Terendah: 1, Tertinggi: 412.
KyleFairns
210

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

Ia bekerja karena valueOfmetode kustom yang disebut ketika Objek dibandingkan dengan primitif (seperti Nomor). Trik utamanya adalah a.valueOfmengembalikan nilai baru setiap kali karena memanggil execekspresi reguler dengan gflag, yang menyebabkan pembaruan lastIndexekspresi reguler itu setiap kali ditemukan kecocokan. Jadi pertama kalinya this.r.lastIndex == 0, cocok 1dan update lastIndex: this.r.lastIndex == 1, sehingga waktu berikutnya regex akan cocok 2dan sebagainya.

Kos
sumber
22
@Abdillah objek regex akan mengingat indeks terakhir yang cocok, panggil execlagi akan mulai mencari dari indeks itu. MDN tidak begitu jelas.
Simon Chan
Begitu, jadi this.robjek regex mengingat status / indeks. Terima kasih!
Abdillah
Saya akan merekomendasikan untuk meneruskan sebuah string ke exec, bukan bilangan bulat yang harus dirubah.
Bergi
gunakan regex dan sekarang Anda memiliki dua masalah
Aleksey Solovey
191

Hal ini dapat dicapai dengan menggunakan hal-hal berikut dalam lingkup global. Untuk nodejsdigunakan globalalih-alih windowdalam 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.

jontro
sumber
Asumsi ini aadalah properti thisyang sepertinya tidak ada. Jika avariabel lokal (yang terlihat seperti), maka ini tidak akan berfungsi.
jfriend00
1
@ jfriend00 maksudmu jika Anda menempatkan var a; suatu tempat?
jontro
Ya. Referensi a == 1merujuk daripada avariabel di suatu tempat, bukan properti dari this. Meskipun ada tempat aneh seperti global di mana keduanya bisa benar, secara umum, mendeklarasikan variabel dengan var aatau let aberarti tidak ada thisyang memungkinkan Anda mengakses asebagai 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.
jfriend00
@ jfriend00 juga yakin. Tidak yakin itu akan menambah nilai lebih banyak dalam kombinasi dengan jawaban lain yang sudah ada. Akan memperbarui jawabannya
jontro
14
Pertanyaannya adalah, mungkinkah ini "pernah" benar. Dan jawabannya adalah ya, dan ini adalah salah satu skenario di mana itu mungkin benar: abukan variabel lokal dan didefinisikan pada lingkup global dengan pengambil yang bertambah.
Zac Delventhal
190

Ini dimungkinkan jika variabel asedang 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 atepat pada waktunya sehingga kondisinya a==1, a==2dana==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

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

pekerja.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, ini terjadi setelah sekitar 10 miliar iterasi pada upaya pertama:

masukkan deskripsi gambar di sini

Usaha kedua:

masukkan deskripsi gambar di sini

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 == 2dan ubah Math.random()*3ke Math.random()*2. Menambahkan lebih banyak dan lebih banyak lagi ke daftar akan mengurangi peluang untuk memukul.

mehulmpt
sumber
50
Jujur, ini jawaban terbaik. Semua jawaban lain memerlukan upaya yang disengaja untuk melakukan sesuatu yang sangat tidak intuitif. Jawaban ini sebenarnya mencerminkan sesuatu yang mungkin terjadi di dunia nyata - kondisi balapan.
Tom Swirly
34
Bukan hanya itu - Saya sebenarnya melihat ini terjadi di dunia nyata. Tidak dengan kondisi yang tepat dalam pertanyaan, tetapi tentu dengan memeriksa (a == 1) pada awal fungsi dan (a == 2) nanti dalam fungsi, dan memiliki kode mengenai kedua kondisi. FYI, pertama kali saya melihat ini terjadi adalah di pengontrol mesin mobil, dan kami menerapkan standar pengkodean. Kali kedua adalah sistem dispenser sekam dan suar untuk pesawat militer, dan pada hari pertama saya di perusahaan saya menemukan ini dan memperbaikinya, sementara anggota tim lainnya masih membahas masalah tersebut. (Level Kudos: tinggi! :)
Graham
38
Jadi, Anda telah bekerja pada "pengendali mesin mobil" dan "sistem dispenser sekam dan flare" yang diprogram dalam javascript dengan pekerja web? Saya tidak berpikir saya akan keluar lagi.
psaxton
12
@psaxton :) Tentu saja tidak - tetapi kami memiliki perangkat lunak multi-utas dengan data bersama. Ini adalah anti-pola untuk semua perangkat lunak multi-utas, tidak khusus untuk Javascript atau untuk pekerja web. Tidak masalah apakah Anda pemrograman dalam bahasa assembly, Brainf * ck, Visual BASIC, C atau Javascript - jika Anda melakukan ini dengan data bersama dalam aplikasi multi-utas, itu akan selalu gagal.
Graham
4
Saya pikir ini sekarang adalah pembungkus rumit jawaban @ jontro.
qntm
148

Ini juga dimungkinkan dengan menggunakan serangkaian pengambil tulisan sendiri:

(Ini mirip dengan solusi jontro, tetapi tidak memerlukan variabel counter.)

(() => {
    "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.");
    }
})();

Patrick Dark
sumber
61
Perhatikan bahwa pendekatan menggunakan rajin dan rajin bekerja juga ===, bukan hanya ==.
Makyen
Solusi ini bergantung pada thismenjadi objek global di dalam tubuh fungsi panah.
Roy Tinker
@ Midnightas saya tidak akan mengkategorikan jawaban lain sebagai "kode piramida" .
Patrick Roberts
Perhatikan ini juga berfungsi dengan perintah sewenang-wenang, bukan? Seperti (a == 3 && a == 2 && a == 1),?
Johannes
131

Atau, Anda bisa menggunakan kelas untuk itu dan contoh untuk cek.

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

Menggunakan kelas ES6 akan terlihat seperti ini

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

Nina Scholz
sumber
5
hanya function A() {value = 0;di awal?
Dave C
valueOfsedang diganti, this method is usually called automatically by JavaScript behind the scenes, and not explicitly in codejadi ketika kita membandingkan nilai itu sebenarnya menambah ..
Danyal Sandeelo
130

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.

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

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 A
- Lebar Penuh Huruf kecil Latin A
а - Huruf kecil Sirilik A

Istilah 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) vs wikipedia.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.

Draco tidak lagi percaya pada SE
sumber
19
"Sedikit perbedaan" bukanlah bagaimana saya menyebutnya.
4
@ Hvd Sepenuhnya tergantung pada rendering font Anda. Ini yang saya lihat .
Draco18s tidak lagi mempercayai SE
1
@Jake Yeah, Lebar Penuh Latin huruf kecil A bukan homoglyph terbesar (tapi varian huruf kapital luar biasa). Meskipun umumnya Anda hanya perlu dua untuk mendapatkan efek yang diinginkan.
Draco18s tidak lagi mempercayai SE
@ Draco18s Setuju ulang: hanya 2 yang biasanya diperlukan. Kerja bagus di info tambahan juga!
JakeSteam
10
Anda juga dapat menggunakan pemilih varian unicode (U + FE00..U + FE0F). Tak satu pun dari ini adalah a: a︀ a︁ a︂. Tidak ada lagi kekhawatiran tentang perbedaan.
Salman A
108

Ya itu mungkin! 😎

»JavaScript

if‌=()=>!0;
var a = 9;

if‌(a==1 && a== 2 && a==3)
{
    document.write("<h1>Yes, it is possible!😎</h1>")
}

Kode di atas adalah versi singkat (terima kasih kepada @Forivin untuk catatannya di komentar) dan kode berikut ini asli:

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

Jika Anda hanya melihat sisi atas kode saya dan menjalankannya, Anda katakan WOW, bagaimana?

Jadi saya pikir sudah cukup untuk mengatakan Ya, itu mungkin bagi seseorang yang mengatakan kepada Anda: Tidak ada yang mustahil

Trik: Saya menggunakan karakter tersembunyi setelah ifmembuat fungsi yang namanya mirip if. Di JavaScript kita tidak bisa mengesampingkan kata kunci jadi saya terpaksa menggunakan cara ini. Ini palsu if, tetapi ini bekerja untuk Anda dalam kasus ini!


» C #

Saya juga menulis versi C # ( dengan teknik peningkatan nilai properti ):

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

Demo Langsung

RAM
sumber
56
Versi javascript adalah kejahatan nyata terhadap kemanusiaan dan kemampuan untuk melakukan ini, harus ilegal oleh Konvensi PBB. Saya pikir sudah saatnya kita membersihkan dunia dari semua pengetahuan tentang javacript.
jelas
2
Deklarasi fungsi bisa lebih pendek. if‌=()=>!0
Forivin
4
Kenapa Anda menggunakan document.write? Cara yang pasti untuk tidak dipekerjakan terlepas dari sisa jawabannya.
Cerbrus
3
@ Cirrus, Terima kasih atas catatan Anda. Saya menulis dulu jawaban saya dengan console.logtetapi saya mengubahnya menjadi document.write. Benar-benar selalu saya gunakan console.logdalam 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 oleh console.log. Klik Run Code Snippettombol 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.
RAM
1
@Clearer, Jika Konvensi PBB dapat mengubah dunia secara efektif, maka kita harus memiliki dunia yang lebih baik daripada ini. Kita perlu sesuatu lebih dari pernyataan di PBB dan sampai hari itu saya pikir kita bisa menggunakan trik Javascript ini;)
RAM
97

JavaScript

a == a +1

Dalam JavaScript, tidak ada bilangan bulat tetapi hanyaNumber s, yang diimplementasikan sebagai angka floating point presisi ganda.

Ini berarti bahwa jika suatu Angka acukup besar, itu dapat dianggap sama dengan tiga bilangan bulat berturut-turut:

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

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==3solusi di Ruby dan Python. Dengan sedikit modifikasi, itu juga mungkin di Jawa.

Rubi

Dengan kebiasaan ==:

class A
  def ==(o)
    true
  end
end

a = A.new

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

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

Jawa

Dimungkinkan untuk memodifikasi Integercache Java :

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.");
        }
    }
}
Eric Duminil
sumber
27
@ cᴏʟᴅsᴘᴇᴇᴅ: Java, Javascript, potayto, potahto :) Sudah ada cukup jawaban JS yang bagus. Saya hanya berpikir itu akan menarik untuk menunjukkan bagaimana hal itu dapat dilakukan dalam bahasa lain, dan mungkin memberikan beberapa pengembang JS ide.
Eric Duminil
2
@ cᴏʟᴅsᴘᴇᴇᴅ: Diperbarui dengan contoh JS.
Eric Duminil
1
Mengapa versi Java tidak bekerja dengan Integer a = 42(atau melakukannya)? Seperti yang saya mengerti autoboxing, Integer a = 42; a == 1 && a == 2 && a == 3harus mengotak semua int. Atau apakah ini unbox a untuk perbandingan?
CAD97
@ CAD97: Integer == intsepertinya menghasilkan unboxing. Tetapi menggunakan Integer#equals(int)kekuatan autoboxing, jadi itu berhasil. Terima kasih atas komentarnya!
Eric Duminil
@StephanBijzitter: Tolong jelaskan. Sejauh yang saya tahu, hanya ada Numbersdi JS, yang pada dasarnya seperti doubles. Mereka bisa terlihat seperti bilangan bulat dan Anda bisa menggunakannya seperti bilangan bulat, tetapi mereka masih bukan bilangan bulat. Saya pikir tidak n == n + 1pernah benar untuk bilangan bulat di Java / Python / C / Ruby / ...
Eric Duminil
80

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, 2dan 3.

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

* 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:

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);
****/

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

Salman A
sumber
75

Peraturan nomor satu wawancara; tidak pernah mengatakan tidak mungkin.

Tidak perlu tipuan karakter tersembunyi.

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?' );
}

MonkeyZeus
sumber
6
Aduh. __defineGetter__sebenarnya bukan bagian dari bahasa js, hanya versi jelek dari defineProperty. typeofbukan fungsi dan ini dideklarasikan ihanya mengerikan. Masih tampaknya bernilai 40 upvotes: /
Jonas Wilms
6
@JonasW. 41 upvotes :-) Saya tahu itu __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 daripada defineProperty()karena kode lama adalah nyata dan tidak dapat diabaikan. Terlepas dari keburukan, menyatakan idalam cara saya lakukan adalah perilaku yang dikenal / didokumentasikan. Mungkin aku sedang dalam mood PCG ¯ \ _ (ツ) _ / ¯
MonkeyZeus
68

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.

Frank W. Zammetti
sumber
13
Pertanyaannya (atau semua pertanyaan wawancara) mungkin untuk menguji kesediaan para kandidat untuk memikirkan masalah, terutama yang "tampaknya jelas", seperti ini. Seseorang yang menolak untuk berpikir karena mereka percaya "tahu" jawabannya bukanlah pekerjaan yang baik.
Shammoo
5
@ Don Hatch Tidak, saya tidak akan menghukum mereka jika mereka menjawab dengan itikad baik dan terutama jika mereka memberikan jawaban yang benar seperti yang telah ditunjukkan orang lain ... tetapi saya kemudian akan meminta tindak lanjut untuk mencoba dan menyelidiki apakah menurut mereka itu cara yang baik untuk menulis kode atau tidak. Menjadi berpengetahuan dan mampu menghasilkan jawaban yang "benar" hanyalah bagian dari menjadi pengembang yang baik. Jauh lebih penting bagi pengembang "profesional" adalah menulis kode yang dapat dimengerti dan dipelihara di ujung jalan, sering kali oleh pengembang yang kurang mampu. Pengembang yang terlalu pintar sama buruknya dengan yang tidak mampu IME.
Frank W. Zammetti
16
Ini tidak menjawab pertanyaan.
TylerH
6
Yang menyedihkan tentang jawaban ini adalah bahwa pengguna 1rep menjawab kemarin dan mendapat 2 downvotes yang menyebabkan dia menghapus pertanyaan ini.
Jonas Wilms
8
@ JohnColeman pertanyaannya bertanya bagaimana kode dapat mengevaluasi ke true. Itu tidak menanyakan alasan pewawancara mengajukan pertanyaan di tempat pertama. Jawaban ini bahkan tidak berusaha menjawab pertanyaan yang diajukan, dan sebaliknya berfokus sepenuhnya pada versi "apa yang akan saya lakukan" dalam upaya menebak apa tujuan pewawancara. Jika itu pertanyaan yang diajukan, itu akan terlalu luas. Karenanya jawaban ini bukan milik sini atau di mana pun di situs.
TylerH
43

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:

  1. 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 fldengan Unicode 'LATIN SMALL LIGATURE FL' (U + FB02)).

  2. 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 .

  3. 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:

  • Efek samping dapat menjadi sangat buruk dan program yang dirancang dengan baik harus bebas dari efek samping yang tidak diinginkan.
  • Keadaan multi-threading dan bisa berubah bisa bermasalah.
  • Tidak melakukan pengkodean karakter dan memproses string dengan benar dapat menyebabkan bug jahat.

1 Misalnya, Anda dapat menemukan contoh dalam bahasa pemrograman yang sama sekali berbeda (C #) yang menunjukkan efek samping (yang jelas) di sini .

Dirk Vollmar
sumber
1
Kemudian, pertanyaannya menjadi terlalu luas. Bahasa yang berbeda dapat menerapkan ini dengan berbagai tingkat kemudahan. Pertanyaannya telah mendapatkan banyak daya tarik karena ini adalah Q&A khusus JS, tapi itu hanya 2c saya.
cs95
1
penyebabnya berbeda C # dan javascript sehingga jawaban ini tidak sah.
Edwin
3
@ Edwin: Penyebabnya persis sama: Unicode mengutak-atik mesin terbang yang mirip atau karakter ruang, kondisi ras, atau efek samping dari operasi perbandingan (yang terakhir ditunjukkan dalam contoh saya).
Dirk Vollmar
2
@ cᴏʟᴅsᴘᴇᴇᴅ: Terkadang melihat sesuatu dari sudut yang lebih luas membantu melihat masalah sebenarnya.
Dirk Vollmar
3
Saya berharap jawaban ini dapat ditandai untuk pertanyaan ini dalam beberapa cara "meta". Setelah membaca semua jawaban di atas itu, aku ditinggalkan perasaan seperti JS memiliki begitu banyak lubang, tapi Anda hanya menyimpulkan semua jawaban dalam satu pergi. Dan Anda melakukannya dengan cara yang menjadikan ini menjadi pertanyaan wawancara bintang (jika tag khusus bahasa dihapus) menurut pendapat saya. Bravo!
KCE
41

Berikut variasi lain, menggunakan array untuk memunculkan nilai apa pun yang Anda inginkan.

const a = {
  n: [3,2,1],
  toString: function () {
    return a.n.pop();
  }
}

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

Théophile
sumber
31

Oke, peretasan lain dengan generator:

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

BaggersIO
sumber
Anda mengatakan retas, tapi saya cukup yakin ini adalah kasus penggunaan generator ... :) (kecuali, ini bergantung pada thisobjek jendela)
Cody G
29

Menggunakan 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);

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 asaat ==memaksa jenisnya untuk membandingkannya dengan setiap nomor. Ini terjadi:

  1. Kami membuat objek target { i: 0 },, di manai properti adalah counter kami
  2. Kami membuat Proxy untuk objek target dan menugaskannya a
  3. Untuk setiap a ==perbandingan, atipe dipaksa ke nilai primitif
  4. Jenis paksaan ini menghasilkan panggilan a[Symbol.toPrimitive]()internal
  5. Proxy mencegat mendapatkan a[Symbol.toPrimitive]fungsi menggunakan "get handler"
  6. "Mendapatkan penangan" cek Proxy bahwa properti yang mendapatkan adalah 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:

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

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.

IceCreamAnda
sumber
2
Tidak ada gunanya menggunakan proxy untuk ini, meskipun - mendefinisikan Symbol.toPrimitivedengan cara yang sama pada suatu objek akan bekerja juga.
Ry-
27

Sebenarnya jawaban untuk bagian pertama dari pertanyaan adalah "Ya" di setiap bahasa pemrograman. Sebagai contoh, ini dalam kasus 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;
}
Gustavo Rodríguez
sumber
27
Saya rasa itu tidak mungkin di setiap bahasa pemrograman. Tidak semua bahasa memiliki preprosesor, misalnya. Untuk itu, tidak semua bahasa digunakan &&untuk logika "dan".
Keith Thompson
3
Saya menemukan cara yang bekerja baik di Python dan C ++ yang menggunakan operator yang berlebihan.
Donald Duck
7
Dan Anda dapat melakukannya di Java dengan menggunakan refleksi dan mengacaukan cache integer.
CAD97
7
Tidak dapat melakukannya dalam bahasa yang tidak mendukung mutasi di tempat itu, mis. Tidak ada yang sebanding tersedia di haskell
Jason Carr
4
Pertanyaannya adalah bertanya tentang JavaScript, bukan C ++.
Semua Pekerja Penting sekali
26

Sama, tetapi berbeda, tetapi tetap sama (dapat "diuji" beberapa kali):

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

Ide saya mulai dari bagaimana persamaan tipe objek Nomor bekerja.

Preda7 atau
sumber
4
Bekerja kedua kalinya juga!
Salman A
25

Sebuah jawaban ECMAScript 6 yang memanfaatkan Simbol:

const a = {value: 1};
a[Symbol.toPrimitive] = function() { return this.value++ };
console.log((a == 1 && a == 2 && a == 3));

Karena ==penggunaan, JavaScript seharusnya memaksa amenjadi sesuatu yang dekat dengan operan kedua ( 1, 2, 3dalam hal ini). Tetapi sebelum JavaScript mencoba mencari paksaan sendiri, ia mencoba menelepon Symbol.toPrimitive. Jika Anda memberikan Symbol.toPrimitiveJavaScript akan menggunakan nilai yang dikembalikan fungsi Anda. Jika tidak, JavaScript akan memanggil valueOf.

Omar Alshaker
sumber
24

Saya pikir ini adalah kode minimal untuk mengimplementasikannya:

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

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

Membuat objek dummy dengan kebiasaan valueOfyang menambah variabel global ipada setiap panggilan. 23 karakter!

Gafi
sumber
14

Yang ini menggunakan defineProperty dengan efek samping yang bagus yang menyebabkan variabel global!

var _a = 1

Object.defineProperty(this, "a", {
  "get": () => {
    return _a++;
  },
  configurable: true
});

console.log(a)
console.log(a)
console.log(a)

Ben Aubin
sumber
8
Anda bisa menggunakan penutupan atas a: get: (a => () => ++a)(0),tidak perlu global.
Nina Scholz
13
@NinaScholz yakin, tapi kita sedang berbicara tentang praktik buruk di sini - biarkan saya memilikinya: D
Ben Aubin
1

Dengan mengesampingkan valueOfdeklarasi kelas, itu dapat dilakukan:

class Thing {
    constructor() {
        this.value = 1;
    }

    valueOf() {
        return this.value++;
    }
}

const a = new Thing();

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

Yang terjadi adalah yang valueOfdisebut di setiap operator perbandingan. Pada yang pertama, aakan sama 1, pada yang kedua, aakan sama 2, dan seterusnya dan seterusnya, karena setiap kali valueOfdipanggil, nilai abertambah.

Oleh karena itu console.log akan aktif dan keluaran (di terminal saya) Thing: { value: 4}, menunjukkan syarat itu benar.

Jonathan Kuhl
sumber