Что делает ~~ ( "двойная тильда" ) в Javascript?

Я сегодня просматривал библиотеку физики онлайн-игр и наткнулся на оператора ~~. Я знаю, что один ~ является побитовым NOT, это сделает NOT OF NOT, который бы отдал то же значение, не так ли?

Ответ 1

Он удаляет все после десятичной точки, потому что побитовые операторы неявно конвертируют свои операнды в 32-битные целые числа. Это работает независимо от того, являются ли операнды числами или строками с плавающей запятой, а результатом является число.

Другими словами, он дает:

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

только если x находится между - (2 31) и 2 31 - 1. В противном случае произойдет переполнение и число будет "обернуться".

Это может считаться полезным для преобразования аргумента строки функции в число, но оба из-за возможности переполнения и что это неверно для использования с нецелыми, я бы не использовал его таким образом, за исключением "кода гольфа" "(т.е. бессмысленно обрезание байтов с исходного кода вашей программы за счет удобочитаемости и надежности). Вместо этого я использовал бы +x или Number(x).


Как это НЕ NOT

Число -43.2, например:

-43.2 10= 11111111111111111111111111010101 2

как подписанное (два дополнения) 32-битное двоичное число. (JavaScript игнорирует то, что после десятичной точки.) Инвертирование бит дает:

NOT -43 10= 00000000000000000000000000101010 2= 42 10

Инвертирование снова дает:

NOT 42 10= 11111111111111111111111111010101 2= -43 10

Это отличается от Math.floor(-43.2) тем, что отрицательные числа округлены до нуля, а не от него. (Функция пол, равная -44, всегда округляется до следующего нижнего целого, независимо от того, является ли это число положительным или отрицательным.)

Ответ 2

Первый оператор ~ принуждает операнд к целому числу (возможно, после принуждения значения к строке или логическому), а затем инвертирует самые младшие 31 бит. Официально номера ECMAScript являются плавающей точкой, но некоторые числа реализованы как 31-битные целые числа в движке SpiderMonkey.

Вы можете использовать его, чтобы превратить массив из 1 элемента в целое число. Плавающие точки преобразуются в соответствии с правилом C, т.е. усечение дробной части.

Второй оператор ~ инвертирует бит обратно, поэтому вы знаете, что у вас будет целое число. Это не то же самое, что принудительное значение boolean в выражении условия, потому что пустой объект {} имеет значение true, а ~~ {} - 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

Ответ 3

Кажется, что ~ выполняет -(N+1). Итак, ~2 == -(2 + 1) == -3 Если вы сделаете это снова на -3, он вернет его обратно: ~-3 == -(-3 + 1) == 2 Вероятно, он просто преобразует строку в число раундом.

Смотрите эту тему: http://www.sitepoint.com/forums/showthread.php?t=663275

Кроме того, более подробная информация доступна здесь: http://dreaminginjavascript.wordpress.com/2008/07/04/28/

Ответ 4

В ECMAScript 6 эквивалент ~~ Math.trunc:

Возвращает неотъемлемую часть числа, удаляя любые дробные цифры. Он не округляет числа.

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

Ответ 5

При заданном ~N есть -(N+1), ~~N тогда -(-(N+1) + 1). Это, очевидно, приводит к опрятной трюке.

Ответ 6

Вот пример того, как этот оператор можно эффективно использовать, где имеет смысл его использовать:

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

Источник:

См. раздел Взаимодействие с точками

Ответ 7

Просто предупреждение. Другие ответы здесь вызвали у меня проблемы.

Цель состоит в том, чтобы удалить что-либо после десятичной точки числа с плавающей запятой, но в ней есть некоторые угловые случаи, которые делают ее опасной ошибкой. Я бы рекомендовал избегать ~~.

Во-первых, ~~ не работает на очень больших числах.

~~1000000000000 == -727279968

В качестве альтернативы используйте Math.trunc() (как упоминал Гайус, Math.trunc() возвращает целочисленную часть числа с плавающей запятой, но доступен только в JavaScript, совместимом с ECMAScript 6). Вы всегда можете сделать свой собственный Math.trunc() для сред, не относящихся к ECMAScript-6, сделав это:

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

Ответ 8

Преобразование строк в числа

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

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

источник

Ответ 9

Тильда (~) имеет алгоризм - (N + 1)

Для справки:

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

Двойная тильда - (- (N + 1) +1)

Например:

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

Тройная тильда - (- (- (N + 1) +1) +1)

Например:

~~~2 = -(-(-(2+1)+1)+1) = -3
~~~3 = -(-(-(3+1)+1)+1) = -4