~ ~ (Đôi khi dấu ngã) làm gì trong Javascript?


Câu trả lời:


248

Nó loại bỏ mọi thứ sau dấu thập phân vì các toán tử bitwise ngầm chuyển đổi toán hạng của chúng thành các số nguyên 32 bit đã ký. Điều này hoạt động cho dù các toán hạng là số (dấu phẩy động) hoặc chuỗi và kết quả là một số.

Nói cách khác, nó mang lại:

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

chỉ khi x nằm giữa - (2 31 ) và 2 31 - 1. Nếu không, tràn sẽ xảy ra và số sẽ "bao quanh".

Điều này có thể được coi là hữu ích để chuyển đổi đối số chuỗi của hàm thành số, nhưng cả hai vì khả năng tràn và không chính xác khi sử dụng với người không có số nguyên, tôi sẽ không sử dụng cách đó ngoại trừ "mã golf" ( nghĩa là cắt xén các byte một cách vô nghĩa khỏi mã nguồn của chương trình của bạn với chi phí dễ đọc và mạnh mẽ). Tôi sẽ sử dụng +xhoặc Number(x)thay vào đó.


Làm thế nào đây là KHÔNG của KHÔNG

Số -43.2, ví dụ:

-43,2 10 = 1111111111111111111111111111010101 2 2

dưới dạng số nhị phân 32 bit đã ký (bổ sung hai). (JavaScript bỏ qua những gì sau dấu thập phân.) Đảo ngược các bit cho:

KHÔNG -43 10 = 00000000000000000000000000101010 2 = 42 10

Đảo ngược một lần nữa cho:

KHÔNG 42 10 = 11111111111111111111111111010101 2 = -43 10

Điều này khác với Math.floor(-43.2)các số âm được làm tròn về 0, không cách xa nó. (Hàm sàn, sẽ bằng -44, luôn làm tròn xuống số nguyên thấp hơn tiếp theo, bất kể số đó là dương hay âm.)


6
Có thể nói, ~~là một cách tốc ký (và có thể là một giải pháp tốt?) Để tạo ra một chức năng cắt ngắn , nhưng rõ ràng là trong javascript .
ruffin

4
JSLint sẽ phàn nàn về việc sử dụng ~~.
Richard Cook

1
Hãy thử Math.trunc ()
Xitalogy

30

Toán tử ~ đầu tiên buộc toán hạng thành một số nguyên (có thể sau khi ép giá trị thành chuỗi hoặc boolean), sau đó đảo ngược 31 bit thấp nhất. Chính thức các số ECMAScript đều là dấu phẩy động, nhưng một số số được triển khai dưới dạng số nguyên 31 bit trong công cụ SpiderMonkey.

Bạn có thể sử dụng nó để biến mảng 1 phần tử thành số nguyên. Điểm nổi được chuyển đổi theo quy tắc C, nghĩa là. cắt ngắn của phần phân đoạn.

Toán tử thứ hai ~ sau đó đảo ngược các bit trở lại, vì vậy bạn biết rằng bạn sẽ có một số nguyên. Điều này không giống như ép buộc một giá trị thành boolean trong một câu lệnh điều kiện, bởi vì một đối tượng trống {} đánh giá là đúng, trong khi ~ ~ {} đánh giá là sai.

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
Cảm ơn tất cả các ví dụ ở đây Shanti, nó thực sự đã giúp ích!
Shane Tomlinson

6
cũng~~undefined // 0
hung hăng

1
cũng vậy~~null // 0
chovy

Về mặt kỹ thuật bạn có thứ tự sai. Thứ hai ~làm những gì bạn mô tả đầu tiên ~làm và ngược lại. Các ~nhà điều hành là một nhà khai thác unary và được interpereted từ phải sang trái ~~Xcũng giống như ~(~X)không thích (~~)X(mà sẽ là một lỗi cú pháp)
yunzen

20

Trong ECMAScript 6, tương đương với ~~Math.trunc :

Trả về phần tích phân của một số bằng cách loại bỏ bất kỳ chữ số phân số nào. Nó không làm tròn bất kỳ số nào.

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

Các polyfill:

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

6
Thật đáng ngạc nhiên, ~ ~ nhanh hơn Math.trunc, jsperf.com/math-trunc-vs-double-bitwise-not-operator . Mặc dù, không phải tất cả mọi thứ là về tốc độ; dễ đọc quá.
Gajus

3
Có một sự khác biệt quan trọng giữa ~ ~ và Math.trunc: nếu bạn truyền một chuỗi hoặc NaN hoặc bất cứ thứ gì không phải là số, Math.trunc sẽ trả về NaN và ~ ~ sẽ luôn trả về một số, trong những trường hợp đó, nó sẽ luôn trả về một số sẽ trở về 0.
Buzinas 19/03/2016

Math.trunc nhanh hơn một chút so với ~ ~ trong Chrome 59+, theo jsperf.com/math-trunc-vs-double-bitwise-not-operator .
Jack Steam

12

Việc này ~dường như để làm -(N+1). Vì vậy, ~2 == -(2 + 1) == -3nếu bạn làm lại trên -3, nó sẽ quay lại: ~-3 == -(-3 + 1) == 2Nó có thể chỉ chuyển đổi một chuỗi thành một số theo cách vòng.

Xem chủ đề này: http://www.sitepoint.com/forums/showthread.php?t=663275

Ngoài ra, thông tin chi tiết hơn có sẵn ở đây: http://dreaminginjavascript.wordpress.com/2008/07/04/28/


Cảm ơn các liên kết Drackir!
Shane Tomlinson


3

Chỉ là một chút cảnh báo. Các câu trả lời khác ở đây khiến tôi gặp một số rắc rối.

Mục đích là để loại bỏ bất cứ thứ gì sau dấu thập phân của số dấu phẩy động, nhưng nó có một số trường hợp góc làm cho nó trở thành một lỗi nguy hiểm. Tôi khuyên bạn nên tránh ~ ~.

Đầu tiên, ~ ~ không hoạt động với số lượng rất lớn.

~~1000000000000 == -727279968

Cách khác, sử dụng Math.trunc()(như Gajus đã đề cập, Math.trunc()trả về phần nguyên của số dấu phẩy động nhưng chỉ khả dụng trong JavaScript tuân thủ ECMAScript 6). Bạn luôn có thể tự tạo cho riêng mình Math.trunc()các môi trường không phải ECMAScript-6 bằng cách này:

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

Tôi đã viết một bài đăng trên blog này để tham khảo: http://bitlords.blogspot.com/2016/08/the-double-tilde-x-technique-in.html


1

Dưới đây là một ví dụ về cách sử dụng toán tử này một cách hiệu quả, nơi sử dụng hợp lý:

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

Nguồn:

Xem phần Tương tác với điểm


1

Chuyển đổi chuỗi thành số

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 là 0

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

nguồn


1

Tilde (~) có một algorihm - (N + 1)

Đối với kỳ thi:

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

Dấu ngã kép là - (- (N + 1) +1)

Ví dụ:

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

Dấu ngã ba là - (- (- (N + 1) +1) +1)

Ví dụ:

~~~2 = -(-(-(2+1)+1)+1) = -3
~~~3 = -(-(-(3+1)+1)+1) = -4
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.