Как!!~ (а не тильда / взрыва взрыва) изменяет результат вызова метода "содержит / включен" в массиве?
Если вы читаете комментарии в 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