Ada Paksaan di Dunia JavaScript - Kisah Detektif
Nathan, Anda tidak tahu apa yang telah Anda temukan.
Saya sudah menyelidiki ini selama berminggu-minggu sekarang. Semuanya dimulai pada malam badai Oktober lalu. Saya tidak sengaja menemukan Numberkelas - Maksud saya, mengapa di dunia ini JavaScript memiliki Numberkelas?
Saya tidak siap untuk apa yang akan saya cari tahu selanjutnya.
Ternyata JavaScript, tanpa memberi tahu Anda, telah mengubah angka Anda menjadi objek dan objek Anda menjadi angka tepat di bawah hidung Anda.
JavaScript berharap tidak ada yang akan menangkap, tetapi orang-orang telah melaporkan perilaku aneh yang tak terduga, dan sekarang terima kasih untuk Anda dan pertanyaan Anda. Saya punya bukti yang saya butuhkan untuk membuat hal ini terbuka lebar.
Inilah yang kami temukan sejauh ini. Saya tidak tahu apakah saya harus mengatakan ini kepada Anda - Anda mungkin ingin mematikan JavaScript Anda.
> function dis() { return this }
undefined
Ketika Anda membuat fungsi itu, Anda mungkin tidak tahu apa yang akan terjadi selanjutnya. Semuanya tampak baik-baik saja, dan semuanya baik-baik saja - untuk saat ini.
Tidak ada pesan kesalahan, hanya kata "tidak terdefinisi" dalam output konsol, persis apa yang Anda harapkan. Bagaimanapun, ini adalah deklarasi fungsi - tidak seharusnya mengembalikan apa pun.
Tapi ini baru permulaan. Apa yang terjadi selanjutnya, tidak ada yang bisa memprediksi.
> five = dis.call(5)
Number {[[PrimitiveValue]]: 5}
Ya saya tahu, Anda mengharapkan 5, tetapi bukan itu yang Anda dapatkan, apakah itu - Anda punya sesuatu yang lain - sesuatu yang berbeda.
Hal yang sama terjadi pada saya.
Saya tidak tahu harus bagaimana. Itu membuatku gila. Saya tidak bisa tidur, saya tidak bisa makan, saya mencoba untuk meminumnya, tetapi Mountain Dew tidak akan membuat saya lupa. Itu tidak masuk akal!
Saat itulah saya mengetahui apa yang sebenarnya terjadi - itu adalah paksaan, dan itu terjadi tepat di depan mata saya, tetapi saya terlalu buta untuk melihatnya.
Mozilla mencoba menguburnya dengan meletakkannya di tempat yang mereka tahu tidak akan dilihat siapa pun - dokumentasi mereka .
Setelah berjam-jam membaca dan membaca kembali secara berulang dan membaca kembali, saya menemukan ini:
"... dan nilai-nilai primitif akan dikonversi menjadi objek."
Itu ada di sana polos seperti yang bisa dibilang dalam font Open Sans. Itu call()fungsinya - bagaimana saya bisa sebodoh itu ?!
Nomor saya sama sekali bukan angka. Saat saya menyebarkannya call(), itu menjadi sesuatu yang lain. Itu menjadi ... sebuah objek.
Awalnya saya tidak percaya. Bagaimana ini bisa benar? Tetapi saya tidak bisa mengabaikan bukti yang meningkat di sekitar saya. Itu ada di sana jika Anda hanya melihat:
> five.wtf = 'potato'
"potato"
> five.wtf
"potato"
wtfitu benar. Angka tidak dapat memiliki properti khusus - kita semua tahu itu! Ini hal pertama yang mereka ajarkan padamu di akademi.
Kita seharusnya tahu saat kita melihat output konsol - ini bukan jumlah yang kami pikir itu. Ini adalah seorang penipu - sebuah benda yang lewat sebagai nomor manis kami yang tidak bersalah.
Ini adalah ... new Number(5).
Tentu saja! Itu masuk akal. call()punya pekerjaan untuk dilakukan, dia harus menjalankan fungsi, dan untuk itu dia perlu mengisi this, dia tahu dia tidak bisa melakukan itu dengan angka - dia butuh objek dan dia bersedia melakukan apa pun untuk mendapatkannya, bahkan jika itu berarti memaksa nomor kita. Ketika call()melihat nomornya 5, dia melihat peluang.
Itu adalah rencana yang sempurna: tunggu sampai tidak ada yang melihat dan menukar nomor kami dengan objek yang terlihat seperti itu. Kami mendapat nomor, fungsinya dipanggil, dan tidak ada yang lebih bijak.
Itu benar-benar rencana yang sempurna, tetapi seperti semua rencana, bahkan yang sempurna, ada lubang di dalamnya, dan kami akan jatuh ke dalamnya.
Lihat, yang call()tidak mengerti adalah bahwa dia bukan satu-satunya di kota yang bisa memaksa angka. Bagaimanapun, ini adalah JavaScript - paksaan ada di mana-mana.
call() mengambil nomor saya, dan saya tidak akan berhenti sampai saya menarik topeng dari penipu kecilnya dan mengekspos dia ke seluruh komunitas Stack Overflow.
Tapi bagaimana caranya? Saya membutuhkan rencana. Tentu itu terlihat seperti angka, tetapi saya tahu tidak, pasti ada cara untuk membuktikannya. Itu dia! Itu terlihat seperti angka, tetapi bisakah itu bertindak seperti nomor?
Saya bilang fivesaya perlu dia menjadi 5 kali lebih besar - dia tidak bertanya mengapa dan saya tidak menjelaskan. Saya kemudian melakukan apa yang akan dilakukan oleh programmer yang baik: Saya mengalikannya. Tentunya tidak mungkin dia bisa menipu jalan keluar dari ini.
> five * 5
25
> five.wtf
'potato'
Sial! Tidak hanya fivemultiply saja wtfmasih ada. Sialan orang ini dan kentangnya.
Apa yang sedang terjadi? Apakah saya salah tentang semua ini? Apakah fivebenar-benar angka? Tidak, saya pasti kehilangan sesuatu, saya tahu itu, ada sesuatu yang harus saya lupakan, sesuatu yang sangat sederhana dan mendasar sehingga saya benar-benar mengabaikannya.
Ini kelihatannya tidak bagus, saya telah menulis jawaban ini selama berjam-jam dan saya masih belum bisa menjelaskan maksud saya. Saya tidak dapat melanjutkan ini, akhirnya orang-orang akan berhenti membaca, saya harus memikirkan sesuatu dan saya harus memikirkannya dengan cepat.
Tunggu, itu saja! fivebukan 25, 25 adalah hasilnya, 25 adalah angka yang sama sekali berbeda. Tentu saja, bagaimana saya bisa lupa? Angka tidak berubah. Ketika Anda melipatgandakan 5 * 5tidak ada yang ditugaskan untuk apa pun yang Anda buat nomor baru 25.
Pasti itu yang terjadi di sini. Entah bagaimana ketika saya mengalikan five * 5, fiveharus dipaksa menjadi angka dan angka itu harus menjadi nomor yang digunakan untuk perkalian. Ini hasil dari perkalian yang dicetak ke konsol, bukan nilai fiveitu sendiri. fivetidak pernah ditugaskan apa pun - jadi tentu saja itu tidak berubah.
Jadi, bagaimana saya bisa fivemenetapkan sendiri hasil operasi. Saya mendapatkannya. fiveBahkan sebelum sempat berpikir, saya berteriak "++".
> five++
5
Aha! Saya memilikinya! Semua orang yang tahu 5 + 1adalah 6, ini adalah bukti yang saya butuhkan untuk mengekspos bahwa fiveitu bukan angka! Itu penipu! Penipu buruk yang tidak tahu bagaimana cara menghitung. Dan saya bisa membuktikannya. Begini cara bilangan real bertindak:
> num = 5
5
> num++
5
Tunggu? Apa yang sedang terjadi disini? desah aku begitu terjebak dalam penghancuran fivesehingga aku lupa bagaimana operator pos bekerja. Ketika saya menggunakan ++di akhir fivesaya katakan kembalikan nilai saat ini, lalu kenaikan five. Ini nilai sebelum operasi terjadi yang akan dicetak ke konsol. numsebenarnya 6dan saya bisa membuktikannya:
>num
6
Saatnya untuk melihat apa yang fivesebenarnya:
>five
6
... persis seperti apa yang seharusnya. fivebagus - tapi saya lebih baik. Jika fivemasih ada objek yang berarti masih memiliki properti wtfdan saya berani bertaruh semua yang tidak.
> five.wtf
undefined
Aha! Saya benar. Saya memilikinya! fivedulu nomor - itu bukan obyek lagi. Saya tahu trik multiplikasi tidak akan menghemat waktu ini. Lihat five++benar-benar five = five + 1. Berbeda dengan perkalian, ++operator memberikan nilai five. Lebih khusus, ia memberikannya hasil five + 1yang sama seperti dalam kasus penggandaan mengembalikan angka abadi yang baru .
Aku tahu aku memilikinya, dan hanya untuk memastikan dia tidak bisa keluar dari situ. Saya punya satu tes lagi di lengan baju saya. Jika saya benar, dan fivebenar-benar nomor sekarang, maka ini tidak akan berhasil:
> five.wtf = 'potato?'
'potato?'
Dia tidak akan membodohiku saat ini. Saya tahu potato?akan dicetak ke konsol karena itu adalah hasil tugas. Pertanyaan sebenarnya adalah, apakah wtfmasih ada?
> five.wtf
undefined
Seperti yang saya duga - tidak ada - karena angka tidak dapat ditetapkan sebagai properti. Kami belajar bahwa tahun pertama di akademi;)
Nathan terima kasih. Terima kasih atas keberanian Anda mengajukan pertanyaan ini, akhirnya saya bisa melupakan semua ini dan beralih ke kasus baru.
Seperti ini tentang fungsinya toValue(). Ya Tuhan. Tidaaaak!
++tampaknya mempengaruhi tipe yang mendasarinya