Как!!~ (а не тильда / взрыва взрыва) изменяет результат вызова метода "содержит / включен" в массиве?

Если вы читаете комментарии в jQuery inArray страница здесь, есть интересная декларация:

!!~jQuery.inArray(elm, arr) 

Теперь я считаю, что двойной восклицательный знак преобразует результат в тип booleanсо значением true, То, что я не понимаю, в чем польза от тильды (~) оператор во всем этом?

var arr = ["one", "two", "three"];
if (jQuery.inArray("one", arr) > -1) { alert("Found"); }

Рефакторинг if заявление:

if (!!~jQuery.inArray("one", arr)) { alert("Found"); }

Сломать:

jQuery.inArray("one", arr)     // 0
~jQuery.inArray("one", arr)    // -1 (why?)
!~jQuery.inArray("one", arr)   // false
!!~jQuery.inArray("one", arr)  // true

Я также заметил, что если я положу тильду впереди, результат -2,

~!!~jQuery.inArray("one", arr) // -2

Я не понимаю цели тильды здесь. Может кто-нибудь объяснить это или указать мне на ресурс?

13 ответов

Решение

Оператор тильды вообще не является частью jQuery - это побитовый оператор НЕ в самом JavaScript.

Посмотрите Великую Тайну Тильды (~).

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

Дополнение Two объясняет, как представлять число в двоичном виде. Я думаю, что я был прав.

Есть конкретная причина, которую вы иногда видите ~ применяется перед $.inArray,

В принципе,

~$.inArray("foo", bar)

это более короткий способ сделать

$.inArray("foo", bar) !== -1

$.inArray возвращает индекс элемента в массиве, если первый аргумент найден, и возвращает -1, если он не найден. Это означает, что если вы ищете логическое значение "это значение в массиве?", Вы не можете выполнить логическое сравнение, поскольку -1 - истинное значение, а когда $.inArray возвращает 0 (ложное значение), это означает, что он фактически найден в первом элементе массива.

Применяя ~ побитовый оператор вызывает -1 становиться 0и заставляет 0 становиться `-1. Таким образом, не обнаружение значения в массиве и применение побитового НЕ приводит к ложному значению (0), а все остальные значения возвращают не-0 чисел и будут представлять достоверный результат.

if (~$.inArray("foo", ["foo",2,3])) {
    // Will run
}

И это будет работать как задумано.

!!~expr оценивает false когда expr является -1 иначе true,
Это так же, как expr != -1только сломанный *


Это работает потому, что побитовые операции JavaScript преобразуют операнды в 32-разрядные целые числа со знаком в формате дополнения до двух. таким образом !!~-1 оценивается следующим образом:

   -1 = 1111 1111 1111 1111 1111 1111 1111 1111b // two's complement representation of -1
  ~-1 = 0000 0000 0000 0000 0000 0000 0000 0000b // ~ is bitwise not (invert all bits)
   !0 = true                                     // ! is logical not (true for falsy)
!true = false                                    // duh

Значение, отличное от -1 по крайней мере один бит будет установлен в ноль; инвертирование создаст истинную ценность; применение ! Оператор дважды к истинному значению возвращает логическое значение true.

При использовании с .indexOf() и мы только хотим проверить, если результат -1 или нет:

!!~"abc".indexOf("d") // indexOf() returns -1, the expression evaluates to false
!!~"abc".indexOf("a") // indexOf() returns  0, the expression evaluates to true
!!~"abc".indexOf("b") // indexOf() returns  1, the expression evaluates to true

* !!~8589934591 оценивается как ложное, так что это мерзость не может быть надежно использован для проверки -1,

~foo.indexOf(bar) это обычное сокращение для представления foo.contains(bar) поскольку contains функция не существует

Как правило, приведение к логическому типу не нужно из-за концепции JavaScript "ложных" значений. В этом случае он используется, чтобы заставить вывод функции быть true или же false,

jQuery.inArray() возвращается -1 за "не найдено", чей состав (~) является 0, Таким образом, ~jQuery.inArray() возвращает ложное значение (0) для "не найден" и истинное значение (отрицательное целое число) для "найден". !! затем формализует ложь / правду в настоящий логический false/true, Так, !!~jQuery.inArray() дам true для "найдено" и false для "не найден".

~ для всех 4 байтов int равен этой формуле -(N+1)

ТАК

~0   = -(0+1)   // -1
~35  = -(35+1)  // -36 
~-35 = -(-35+1) //34 

Тильда поразрядна НЕ - она ​​инвертирует каждый бит значения. Как правило, если вы используете ~ на числе его знак будет инвертирован, затем 1 будет вычтен.

Таким образом, когда вы делаете ~0, вы получите -1 (0 инвертировано -0, вычитание 1 равно -1).

По сути, это сложный, супер-микро-оптимизированный способ получения значения, которое всегда является логическим.

~ оператор - оператор побитового дополнения. Целочисленный результат от inArray() либо -1, когда элемент не найден, либо некоторое неотрицательное целое число. Побитовое дополнение -1 (представленное в двоичном виде как все 1 бит) равно нулю. Побитовое дополнение любого неотрицательного целого числа всегда ненулевое.

Таким образом, !!~i будет true когда целое число "i" является неотрицательным целым числом, и false когда "я" точно -1.

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

Вы правы: этот код вернется false когда indexOf вызов возвращает -1; иначе true,

Как вы говорите, было бы гораздо разумнее использовать что-то вроде

return this.modifiedPaths.indexOf(path) !== -1;

~ оператор - побитовый оператор НЕ. Это означает, что оно принимает число в двоичной форме и превращает все нули в единицы, а единицы в нули.

Например, число 0 в двоичном 0000000в то время как -1 11111111, Аналогично, 1 00000001 в двоичном виде, в то время как -2 11111110,

Я думаю, что он там, потому что он на несколько символов короче (какие авторы библиотеки всегда следуют). Он также использует операции, которые занимают всего несколько машинных циклов при компиляции в собственный код (в отличие от сравнения с числом).

Я согласен с другим ответом, что это излишнее, но, возможно, может иметь смысл в узком цикле (хотя требуется оценка прироста производительности, в противном случае может оказаться преждевременной оптимизации).

Я предполагаю, что, поскольку это побитовая операция, это самый быстрый (дешевый в вычислительном отношении) способ проверить, появляется ли путь в ifiedPaths.

Как (~(-1)) === 0, так:

!!(~(-1)) === Boolean(~(-1)) === Boolean(0) === false
Другие вопросы по тегам