Apa yang dilakukan tilde ketika mendahului ekspresi?

Jawaban:

267

~adalah operator bitwise yang membalik semua bit di operan.

Misalnya, jika nomor Anda adalah 1, representasi biner dari float IEEE 754 (bagaimana JavaScript memperlakukan angka) akan ...

0011 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

Jadi ~konversikan operan ke integer 32 bit (operator bitwise dalam JavaScript melakukan itu) ...

0000 0000 0000 0000 0000 0000 0000 0001

Jika itu adalah angka negatif, itu akan disimpan dalam komplemen 2's: membalikkan semua bit dan menambahkan 1.

... dan kemudian membalik semua bagiannya ...

1111 1111 1111 1111 1111 1111 1111 1110

Jadi apa gunanya itu? Kapan seseorang bisa menggunakannya?

Ini memiliki beberapa kegunaan. Jika Anda menulis hal-hal tingkat rendah, ini berguna. Jika Anda membuat profil aplikasi Anda dan menemukan hambatan, itu bisa dibuat lebih berkinerja dengan menggunakan trik bitwise (sebagai salah satu alat yang mungkin dalam tas yang jauh lebih besar).

Ini juga merupakan (umumnya) tidak jelas trik untuk mengubah indexOf()'s ditemukan nilai kembali ke truthy (sementara membuat tidak ditemukan sebagai falsy ) dan orang sering menggunakannya untuk efek samping dari truncating nomor ke 32 bit (dan menjatuhkan tempat desimal sebesar dua kali lipat itu, efektif sama dengan Math.floor()untuk angka positif).

Saya katakan tidak jelas karena tidak jelas apa gunanya. Secara umum, Anda ingin kode Anda berkomunikasi dengan jelas kepada orang lain yang membacanya. Meskipun menggunakan ~mungkin terlihat keren , umumnya terlalu pintar untuk kebaikannya sendiri. :)

Ini juga kurang relevan sekarang karena JavaScript telah Array.prototype.includes()dan String.prototype.includes(). Ini mengembalikan nilai boolean. Jika platform target Anda mendukungnya, Anda harus memilih ini untuk menguji keberadaan nilai dalam string atau array.

alex
sumber
2
Apakah kata jahat itu benar? Jika berhasil, saya hanya menyebutnya idiom bahasa. Ada banyak idiom. Setelah Anda mempelajarinya, mereka tidak jelas. Pemahaman daftar tidak jelas dalam Python jika Anda tidak mengetahuinya dan dapat dilakukan dengan loop verbose yang lebih banyak tetapi Anda tidak akan pernah meminta programmer Python untuk tidak menggunakannya. Demikian pula value = value || defaultdalam JavaScript adalah idiom umum dan valid selama Anda tahu kapan Anda bisa dan tidak bisa menggunakannya.
GM
3
@ gman Saya kira itu tidak masalah jika seseorang menggunakannya atau tidak. Saya pikir membandingkan pemahaman daftar (fitur bahasa) dengan ini tidak benar-benar hal yang sama ( cara pintar untuk menghindari mengetik beberapa karakter tambahan). Jika menurut Anda istilah jahat terlalu kasar, silakan edit jawaban saya.
alex
2
Mungkin contoh yang lebih umum adalah v = t ? a : b;. Saya menemukan bahwa jauh lebih jelas daripada var v; if (t} { v = a; } else { v = b; }biasanya menembus 5+ baris dan juga lebih jelas daripada var v = b; if (t) { v = a; }biasanya 4+ baris. Tapi saya tahu banyak orang yang tidak terbiasa dengan ? :operator yang lebih suka cara kedua atau ketiga. Saya menemukan yang pertama lebih mudah dibaca. Saya setuju dengan prinsip umum, jelaskan kodenya, jangan gunakan peretasan. Saya kira saya hanya melihat ~v.indexOf('...')dengan sangat jelas setelah saya mempelajarinya.
GM
9
Ketika Anda bekerja di perusahaan besar dengan banyak pengembang, Anda ingin kode ditulis dengan jelas (BAHASA INDONESIA) dan didokumentasikan dengan baik. Inti dari pengkodean tingkat tinggi dalam bahasa dengan pengumpulan sampah adalah untuk menghindari memikirkan operasi biner, dan banyak pengembang front-end bahkan tidak memiliki pengalaman bahasa assembly di bawah ikat pinggang mereka.
user2867288
3
saya tidak akan menelepon ~idiomatik. itu secara teknis bagian dari spesifikasi bahasa , tapi itu bukan bagian dari bahasa yang umum digunakan .
worc
109

Menggunakannya sebelum indexOf()ekspresi secara efektif memberi Anda hasil yang benar / salah, bukan indeks numerik yang langsung dikembalikan.

Jika nilai kembali -1, maka ~-1adalah 0karena -1adalah string dari semua 1 bit. Nilai apa pun yang lebih besar dari atau sama dengan nol akan memberikan hasil yang tidak nol. Jadi,

if (~someString.indexOf(something)) {
}

akan menyebabkan ifkode berjalan ketika "sesuatu" ada di "someString". Jika Anda mencoba menggunakan .indexOf()sebagai boolean secara langsung, maka itu tidak akan berhasil karena kadang-kadang ia mengembalikan nol (ketika "sesuatu" berada di awal string).

Tentu saja, ini juga berfungsi:

if (someString.indexOf(something) >= 0) {
}

dan itu jauh kurang misterius.

Terkadang Anda juga akan melihat ini:

var i = ~~something;

Menggunakan ~operator dua kali seperti itu adalah cara cepat untuk mengubah string ke integer 32-bit. Yang pertama ~melakukan konversi, dan yang kedua ~membalik bit kembali. Tentu saja jika operator diterapkan pada sesuatu yang tidak dapat dikonversi ke angka, Anda dapatkan NaNhasilnya. ( sunting - sebenarnya ini yang kedua ~diterapkan pertama kali, tetapi Anda mendapatkan idenya.)

Runcing
sumber
2
Bagi mereka yang tidak ingin meniadakan sedikit demi sedikit, ~ketika dilakukan pada bilangan bulat sama dengan -(x + 1).
Fabrício Matté
Sepertinya, yah, Anda tahu, nilai numerik NEGATIF harus mengembalikan yang boolean negatif juga di tempat pertama. Tapi salah satu dari JS gagal, kurasa?
wwaawaw
7
@adlwalrus adalah tradisi 0keberadaan falsedan bukan-nol yang trueberasal dari masa lalu, setidaknya sampai C di tahun 70-an dan mungkin banyak bahasa pemrograman sistem kontemporer lainnya. Mungkin berasal dari cara perangkat keras bekerja; banyak CPU menetapkan sedikit nol setelah operasi, dan memiliki instruksi cabang yang sesuai untuk mengujinya.
Runcing
4
Cara yang lebih cepat untuk mengubahnya menjadi int 32 bit adalah | 0, dalam hal ini hanya satu operasi.
alex
@ alex memang, meskipun kami tidak dapat selalu percaya runtime tidak menafsirkan aplikasi sederhana ~~dengan cara yang persis sama.
Runcing
29

Ini ~adalah Bitwise NOT Operator , ~xkira-kira sama dengan -(x+1). Lebih mudah dimengerti, semacam. Begitu:

~2;    // -(2+1) ==> -3

Pertimbangkan -(x+1). -1dapat melakukan operasi itu untuk menghasilkan a 0.

Dengan kata lain, ~digunakan dengan kisaran nilai angka akan menghasilkan nilai falsy (memaksa falsedari 0) hanya untuk nilai -1input, jika tidak, nilai kebenaran lainnya.

Seperti yang kita ketahui, -1biasanya disebut nilai sentinel . Hal ini digunakan untuk banyak fungsi yang mengembalikan >= 0nilai-nilai untuk sukses dan -1untuk kegagalan dalam bahasa C. Yang mana nilai aturan pengembalian yang sama indexOf()dalam JavaScript.

Adalah umum untuk memeriksa ada / tidaknya substring di string lain dengan cara ini

var a = "Hello Baby";

if (a.indexOf("Ba") >= 0) {
    // found it
}
if (a.indexOf("Ba") != -1) { 
    // found it
}

if (a.indexOf("aB") < 0) { 
    // not found
}
if (a.indexOf( "aB" ) == -1) { 
    // not found
}

Namun, akan lebih mudah untuk melakukannya ~seperti di bawah ini

var a = "Hello Baby";

~a.indexOf("Ba");         // -7   -> truthy
if (~a.indexOf("Ba")) {   // true
    // found it
}

~a.indexOf("aB");         // 0    -> falsy
!~a.indexOf("aB");        // true
if (!~a.indexOf( "aB" )) {  // true
    // not found
}

Anda Tidak Tahu JS: Type & Grammar oleh Kyle Simpson

zangw
sumber
1
Ini pasti lebih mudah untuk memahami pada nilai nominal, bahkan jika seseorang tidak memahami latar belakang yang membuatnya bekerja. Saya akan melihat kedua-(x+1) jika saya melihatnya dalam pernyataan if. Tilde memberi tahu saya apa yang dilakukan untuk mengimbangi sifat berbasis-Javascript. Juga, semakin sedikit tanda kurung semakin baik untuk membaca
Reguler Joe
Di blok kode pemeriksaan awal Anda, Anda bisa mengetik lebih sedikit dengan menggunakan if (a.indexOf("Ba") > -1) {// found} //true yang, meskipun sedikit lebih panjang dari contoh tilde, jauh lebih sedikit dari dua contoh yang Anda berikan dan untuk programmer baru dapat var opinion = !~-1 ? 'more' : 'less'dimengerti.
HalfMens
24

~indexOf(item) muncul cukup sering, dan jawabannya di sini luar biasa, tetapi mungkin beberapa orang hanya perlu tahu cara menggunakannya dan "melewatkan" teorinya:

   if (~list.indexOf(item)) {
     // item in list
   } else {
     // item *not* in list
   }
Jorge Bucaran
sumber
1
Saya setuju. Panduan Gaya JavaScript Airbnb dilarang ++dan --karena mereka "mendorong trickiness berlebihan" dan entah bagaimana ~bertahan (bersembunyi di bayang-bayang) github.com/airbnb/javascript/issues/540
Shanimal
@Shanimal Alternatifnya adalah list.indexOf(item) >= 0atau ... > -1karena javascript berbasis nol dan tidak memilih untuk mengatasi ini sejak awal. Lebih jauh, hanya opini (sama seperti Airbnb), siapa pun yang melakukan sesuatu yang bermakna dalam javascript tahu ++, dan meskipun --kurang umum, artinya dapat disimpulkan.
Reguler Joe
@ RegulerJoe Saya setuju dengan sebagian besar dari itu. Saya pribadi tidak membutuhkan ++dan --dalam beberapa waktu karena metode primitif seperti map, forEachdll. Maksud saya adalah lebih banyak tentang mengapa mereka juga tidak menganggap ~terlalu rumit ketika standar apa pun yang digunakan termasuk operator kenaikan dan penurunan. Untuk melarang sesuatu sehingga CIS101 tidak masuk akal.
Shanimal
11

Bagi mereka yang mempertimbangkan menggunakan trik tilde untuk menciptakan nilai kebenaran dari suatu indexOfhasil, itu lebih eksplisit dan memiliki lebih sedikit keajaiban untuk alih-alih menggunakan includesmetode iniString .

'hello world'.includes('hello') //=> true
'hello world'.includes('kittens') //=> false

Perhatikan bahwa ini adalah metode standar baru pada ES 2015 sehingga tidak akan berfungsi pada browser lama. Dalam kasus di mana itu penting, pertimbangkan untuk menggunakan String.prototype.include polyfill .

Fitur ini juga tersedia untuk array menggunakan sintaks yang sama :

['apples', 'oranges', 'cherries'].includes('apples') //=> true
['apples', 'oranges', 'cherries'].includes('unicorns') //=> false

Berikut adalah Array.prototype.include polyfill jika Anda memerlukan dukungan browser yang lebih lama.

Dana Woodman
sumber
2
Hindari menggunakan include (). Ini tidak didukung dalam versi IE apa pun (tidak hanya peramban yang lebih lama) pada saat penulisan: developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Onshop
8
Atau cukup gunakan kompiler, sehingga Anda dapat menulis kode yang lebih jelas, alih-alih menulis bahasa sesuai dengan interpreter JS common denominator terburuk di luar sana ...
Kyle Baker
2
@ Ben benar, itu tidak bekerja di Netscape 4.72.
mikemaccana