Apa yang dilakukan ~~ (“double tilde”) dalam Javascript?


Jawaban:


248

Ini menghapus semuanya setelah titik desimal karena operator bitwise secara implisit mengubah operan mereka menjadi bilangan bulat 32-bit yang ditandatangani. Ini berfungsi baik operan berupa angka atau string, dan hasilnya adalah angka.

Dengan kata lain, itu menghasilkan:

function(x) {
  if(x < 0) return Math.ceil(x);
  else return Math.floor(x);
}

hanya jika x berada di antara - (2 31 ) dan 2 31 - 1. Jika tidak, overflow akan terjadi dan nomor akan "membungkus".

Ini mungkin dianggap berguna untuk mengubah argumen string fungsi menjadi angka, tetapi keduanya karena kemungkinan overflow dan bahwa itu salah untuk digunakan dengan non-integer, saya tidak akan menggunakannya seperti itu kecuali untuk "kode golf" ( yaitu tanpa memotong poin dari kode sumber program Anda dengan mengorbankan keterbacaan dan ketahanan). Saya akan menggunakan +xatau Number(x)sebagai gantinya.


Bagaimana ini BUKAN BUKAN BUKAN

Angka -43.2, misalnya adalah:

-43.2 10 = 11111111111111111111111111010101 2

sebagai nomor biner 32-bit yang ditandatangani (komplemen dua). (JavaScript mengabaikan apa yang setelah titik desimal.) Membalik bit memberi:

TIDAK -43 10 = 0000000000000000000000000010101010 2 = 42 10

Pembalikan lagi memberi:

BUKAN 42 10 = 11111111111111111111111111010101 2 = -43 10

Ini berbeda dari Math.floor(-43.2)angka negatif dibulatkan ke nol, tidak jauh dari itu. (Fungsi lantai, yang akan sama dengan -44, selalu dibulatkan ke bilangan bulat bawah berikutnya, terlepas dari apakah angka tersebut positif atau negatif.)


6
Artinya, ~~adalah cara singkat (dan mungkin solusi yang baik?) Untuk membuat fungsi truncate , tetapi jelas dalam javascript .
ruffin

4
JSLint akan mengeluh tentang penggunaan ~~.
Richard Cook

1
Coba Math.trunc ()
Xitalogy

30

Operator ~ pertama memaksa operan ke integer (mungkin setelah memaksa nilai ke string atau boolean), kemudian membalikkan 31 bit terendah. Nomor ECMAScript resmi semuanya adalah floating-point, tetapi beberapa angka diimplementasikan sebagai bilangan bulat 31-bit di mesin SpiderMonkey.

Anda bisa menggunakannya untuk mengubah array 1 elemen menjadi integer. Floating-point dikonversi sesuai dengan aturan C, yaitu. pemotongan bagian fraksional.

Operator ~ kedua kemudian membalikkan bit kembali, sehingga Anda tahu bahwa Anda akan memiliki integer. Ini tidak sama dengan memaksa nilai ke boolean dalam pernyataan kondisi, karena objek kosong {} bernilai true, sedangkan ~~ {} bernilai false.

js>~~"yes"
0
js>~~3
3
js>~~"yes"
0
js>~~false
0
js>~~""
0
js>~~true
1
js>~~"3"
3
js>~~{}
0
js>~~{a:2}
0
js>~~[2]
2
js>~~[2,3]
0
js>~~{toString: function() {return 4}}
4
js>~~NaN
0
js>~~[4.5]
4
js>~~5.6
5
js>~~-5.6
-5

1
Terima kasih untuk semua contoh di sini, Shanti, ini sangat membantu!
Shane Tomlinson

6
juga~~undefined // 0
rampion

1
juga~~null // 0
chovy

Secara teknis Anda salah urutan. Yang kedua ~melakukan apa yang Anda deskripsikan ~lakukan pertama dan sebaliknya. The ~operator adalah operator unary dan interpereted dari kanan ke kiri ~~Xseperti ~(~X)tidak seperti (~~)X(yang akan menjadi kesalahan sintaks)
yunzen

20

Dalam ECMAScript 6, setara dengan ~~adalah Math.trunc :

Mengembalikan bagian integral dari angka dengan menghapus digit fraksional apa pun. Itu tidak membulatkan angka apa pun.

Math.trunc(13.37)   // 13
Math.trunc(42.84)   // 42
Math.trunc(0.123)   //  0
Math.trunc(-0.123)  // -0
Math.trunc("-1.123")// -1
Math.trunc(NaN)     // NaN
Math.trunc("foo")   // NaN
Math.trunc()        // NaN

Polyfill:

function trunc(x) {
    return x < 0 ? Math.ceil(x) : Math.floor(x);
}

6
Agak mengherankan, ~~ lebih cepat dari Math.trunc, jsperf.com/math-trunc-vs-double-bitwise-not-operator . Padahal, tidak semuanya tentang kecepatan; keterbacaan juga.
Gajus

3
Ada perbedaan penting antara ~~ dan Math.trunc: jika Anda meneruskan string, atau NaN atau hal apa pun yang bukan angka, Math.trunc akan mengembalikan NaN, dan ~~ akan selalu mengembalikan angka, dalam kasus itu, itu akan kembali 0.
Buzinas

Math.trunc sedikit lebih cepat daripada ~~ di Chrome 59+, menurut jsperf.com/math-trunc-vs-double-bitwise-not-operator .
Jack Steam



4

Hanya sedikit peringatan. Jawaban lain di sini membuat saya kesulitan.

Tujuannya adalah untuk menghapus apa pun setelah titik desimal dari angka titik mengambang, tetapi memiliki beberapa kasus sudut yang membuatnya menjadi bahaya bug. Saya sarankan menghindari ~~.

Pertama, ~~ tidak bekerja pada angka yang sangat besar.

~~1000000000000 == -727279968

Sebagai alternatif, gunakan Math.trunc()(seperti yang disebutkan Gajus, Math.trunc()mengembalikan bagian integer dari angka floating point tetapi hanya tersedia di JavaScript yang sesuai dengan ECMAScript 6). Anda selalu dapat membuat sendiri Math.trunc()untuk lingkungan non-ECMAScript-6 dengan melakukan ini:

if(!Math.trunc){
    Math.trunc = function(value){
        return Math.sign(value) * Math.floor(Math.abs(value));
    }
}

Saya menulis posting blog tentang ini untuk referensi: http://bitlords.blogspot.com/2016/08/the-double-tilde-x-technique-in.html


1

Berikut adalah contoh bagaimana operator ini dapat digunakan secara efisien, di mana masuk akal untuk menggunakannya:

leftOffset = -(~~$('html').css('padding-left').replace('px', '') + ~~$('body').css('margin-left').replace('px', '')),

Sumber:

Lihat bagian Berinteraksi dengan poin


1

Mengubah String ke Angka

console.log(~~-1);    // -1
console.log(~~0);     // 0
console.log(~~1);     // 1
console.log(~~"-1");  // -1
console.log(~~"0");   // 0
console.log(~~"1");   // 1
console.log(~~true);  // 1
console.log(~~false); // 0

~ -1 adalah 0

if (~someStr.indexOf("a")) {
  // Found it
} else  {
  // Not Found
}

sumber


1

Tilde (~) memiliki algorihm - (N + 1)

Untuk memeriksa:

~0 = -(0+1) = -1
~5 = -(5+1) = -6
~-7 = -(-7+1) = 6

Double tilde adalah - (- (N + 1) +1)

Sebagai contoh:

~~5 = -(-(5+1)+1) = 5
~~-3 = -(-(-3+1)+1) = -3

Triple tilde adalah - (- (- (N + 1) +1) +1)

Sebagai contoh:

~~~2 = -(-(-(2+1)+1)+1) = -3
~~~3 = -(-(-(3+1)+1)+1) = -4
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.