it-swarm.dev

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

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.

Mungkinkah (a== 1 && a ==2 && a==3) dapat dievaluasi menjadi 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.

2331

Jika Anda memanfaatkan cara kerja == , Anda bisa membuat objek dengan fungsi toString (atau valueOf) kustom 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 kasus 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 jika gagal itu akan memanggil toString. Saya menggunakan toString dalam kasus ini hanya karena itulah yang terlintas dalam pikiran, valueOf akan lebih masuk akal. Jika saya sebaliknya mengembalikan string dari toString, mesin kemudian akan berusaha untuk mengubah string ke angka yang memberi kami hasil akhir yang sama, meskipun dengan jalur yang sedikit lebih panjang.

3185
Kevin B

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 pernyataan if (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 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 _ agar mudah dibaca, 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!")
}

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

Sunting: Telah menjadi perhatian saya bahwa (walaupun tidak diperbolehkan untuk memulai variabel) Zero-width joiner dan Zero-width non-joiner karakter juga diizinkan dalam nama variabel - lihat Mengaburkan JavaScript dengan karakter nol-lebar - 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!")
}

1969
Jeff

IS MUNGKIN!

var i = 0;

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

Ini menggunakan pengambil dalam pernyataan with untuk membiarkan a mengevaluasi tiga nilai 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.");
  }

591
Jonas Wilms

Contoh tanpa getter atau valueOf:

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

Ini berfungsi karena == memanggil toString yang memanggil .join untuk Array.

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

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

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

458
georg

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

259
mmmaaa

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

Ini bekerja karena metode custom valueOf yang dipanggil ketika Object dibandingkan dengan primitive (seperti Number). Trik utamanya adalah a.valueOf mengembalikan nilai baru setiap kali karena memanggil exec pada ekspresi reguler dengan g flag, yang menyebabkan pembaruan lastIndex dari ekspresi reguler itu setiap kali ditemukan kecocokan. Jadi pertama kali this.r.lastIndex == 0, cocok dengan 1 dan pembaruan lastIndex: this.r.lastIndex == 1, jadi waktu berikutnya regex akan cocok dengan 2 dan seterusnya.

203
Kos

Itu dapat dicapai dengan menggunakan yang berikut ini dalam lingkup global. Untuk nodejs gunakan global daripada 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.

186
jontro

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 variabel a tepat pada waktunya sehingga kondisi a==1, a==2 dan a==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:

 enter image description here

Usaha kedua:

 enter image description here

Seperti yang saya katakan, peluangnya akan rendah, tetapi diberikan waktu yang cukup, itu akan mengenai kondisinya.

Tip: Jika terlalu lama pada sistem Anda. Coba a == 1 && a == 2 dan ubah Math.random()*3 menjadi Math.random()*2. Menambahkan lebih banyak dan lebih banyak lagi ke daftar akan mengurangi peluang untuk memukul.

182
mehulmpt

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

145
Patrick Dark

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 a = 2;
var а = 3;
if(a == 1 && a == 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 Bahasa Latin huruf kecil A
а - Huruf kecil Sirilik A

Istilah umum untuk ini adalah "homoglyphs": karakter unicode berbeda yang terlihat sama. Biasanya sulit mendapatkan tiga yang benar-benar tidak dapat dibedakan, tetapi dalam beberapa kasus Anda bisa beruntung. A, Α, А, dan Ꭺ akan bekerja lebih baik (Latin-A, Greek Alpha , Cyrillic-A , dan Cherokee-A masing-masing; sayangnya huruf kecil Yunani dan Cherokee terlalu berbeda dari bahasa Latin a: α, , dan karenanya tidak membantu dengan cuplikan di atas).

Ada seluruh kelas Serangan Homoglyph di luar sana, paling umum dalam nama domain palsu (mis. wikipediа.org (Cyrillic) vs wikipedia.org (Latin)), tetapi dapat juga muncul dalam kode; biasanya disebut sebagai curang (seperti yang disebutkan dalam komentar, [licik] pertanyaan sekarang di luar topik pada PPCG , tetapi dulu merupakan jenis tantangan di mana hal-hal semacam ini akan menunjukkan naik). Saya menggunakan situs web ini untuk menemukan homoglyph yang digunakan untuk jawaban ini.

127
Draco18s

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

123
Nina Scholz

JavaScript

a == a +1

Dalam JavaScript, tidak ada integer tetapi hanya Numbers, 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:

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 a=0), tetapi tidak melibatkan trik dengan fungsi tersembunyi atau kelebihan operator.

Bahasa lainnya

Untuk referensi, ada solusi a==1 && a==2 && a==3 di Ruby dan Python. Dengan sedikit modifikasi, itu juga mungkin di Jawa.

Rubi

Dengan == khusus:

class A
  def ==(o)
    true
  end
end

a = A.new

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

Atau a yang semakin meningkat:

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 Java Integer cache :

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.");
        }
    }
}
93
Eric Duminil

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 kepada seseorang yang berkata kepada. Anda: Tidak ada yang mustahil

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


»C #

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

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

90
RAM

Ini adalah versi terbalik dari @ Jeff's jawaban * di mana karakter tersembunyi (U + 115F, U + 1160 atau U + 3164) digunakan untuk membuat variabel yang terlihat seperti 1, 2 dan 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 non-joiner lebar nol (U + 200C) dan joiner lebar nol (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 mis. dengan menggunakan pemilih variasi Unicode untuk membuat variabel yang terlihat persis sama (a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true).

78
Salman A

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

72
MonkeyZeus

Jujur saja, apakah ada cara untuk mengevaluasi untuk 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 kode berbelit-belit, dan saya berusaha untuk tidak pernah menulis kode 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.

66

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

41
Théophile

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, mis. saat menyalin & menempelkan kode dari Web yang berisi titik kode Unicode yang tidak terduga (mis. karena sistem manajemen konten melakukan beberapa "pemformatan otomatis" seperti mengganti fl dengan Unicode 'LATIN SMALL LIGATURE FL' (U + FB02)).

  2. Kondisi ras: A kondisi ras 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 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 proof-of-concept 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 dari klasik JavaScript WTF di sini1

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 pemrosesan string dengan benar dapat menyebabkan bug jahat.

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

37
Dirk Vollmar

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

31
BaggersIO

Sebenarnya jawaban untuk bagian pertama dari pertanyaan adalah "Ya" di setiap bahasa pemrograman. Misalnya, 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;
}
27

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

  1. Kami membuat objek target, { i: 0 }, di mana properti i adalah counter kami
  2. Kami membuat Proxy untuk objek target dan menetapkannya ke a
  3. Untuk setiap perbandingan a ==, tipe a dipaksa ke nilai primitif
  4. Jenis paksaan ini menghasilkan pemanggilan a[Symbol.toPrimitive]() secara internal
  5. Penyadapan proxy mendapatkan fungsi a[Symbol.toPrimitive] menggunakan "get handler"
  6. "Get handler" Proxy memeriksa bahwa properti yang didapat adalah Symbol.toPrimitive, yang dalam hal ini bertambah dan kemudian mengembalikan penghitung dari objek target: ++target.i. Jika properti lain sedang diambil, kami 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 jenis paksaan yang dapat disadap oleh Proxy.

27
IceCreamYou

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.

26
Preda7or

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 a menjadi sesuatu yang dekat dengan operan kedua (1, 2, 3 dalam kasus ini). Tetapi sebelum JavaScript mencoba mencari paksaan dengan sendirinya, ia mencoba memanggil Symbol.toPrimitive . Jika Anda memberikan Symbol.toPrimitive JavaScript akan menggunakan nilai yang dikembalikan fungsi Anda. Jika tidak, JavaScript akan memanggil valueOf .

23
Omar Alshaker

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 valueOf kustom yang menambah variabel global i pada setiap panggilan. 23 karakter!

23
Gaafar

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)

11
Ben Aubin

Dengan mengganti valueOf dalam deklarasi 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);
}

Apa yang terjadi adalah bahwa valueOf dipanggil di setiap operator perbandingan. Pada yang pertama, a akan sama dengan 1, pada yang kedua, a akan sama dengan 2, dan seterusnya dan seterusnya, karena setiap kali valueOf disebut, nilai a akan bertambah.

Oleh karena itu console.log akan aktif dan menghasilkan (di terminal saya) Thing: { value: 4}, yang menunjukkan bahwa kondisional itu benar.

0
Jonathan Kuhl