понять функцию zepto.matches

В исходном коде zepto я обнаружил, что в функции zepto.matches есть резервное выполнение,

zepto.matches = function(element, selector) {
    if (!element || element.nodeType !== 1) return false
    var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector ||
                          element.oMatchesSelector || element.matchesSelector
    if (matchesSelector) return matchesSelector.call(element, selector)
    // fall back to performing a selector:
    var match, parent = element.parentNode, temp = !parent
    if (temp) (parent = tempParent).appendChild(element)
    match = ~zepto.qsa(parent, selector).indexOf(element)
    temp && tempParent.removeChild(element)
    return match
  }

несмотря на обычный способ matchSelector, мне очень любопытен запасной вариант, почему он добавляет ~ перед этим:
~zepto.qsa(parent, selector).indexOf(element)

   document.getElementById("test");
   $.zepto.matches(a,"#test") // -1

он возвращает -1 , это правильно или я что-то упустил?


person Lanston    schedule 12.04.2013    source источник
comment
Это побитовый оператор NOT. Это небольшой лайфхак, который идеально подходит для indexOf звонков. Если значение, возвращаемое из indexOf, равно -1 (это означает, что оно не было найдено в коллекции/строке), ~-1 равно 0... что логически совпадает с false. Любое другое значение, возвращенное из indexOf (больше -1), ~value будет истинным (то есть оно было найдено). Так что это простой способ поставить indexOf в сравнение   -  person Ian    schedule 12.04.2013


Ответы (1)


Это оператор побитового НЕ. В этом случае используется логическое возвращаемое значение для indexOf: методы indexOf (массив, строка) возвращают -1, если совпадение не найдено, и позицию, если совпадение найдено. Позиция может быть и 0, конечно. Итак, используя побитовый оператор НЕ:

console.log(~-1); // 0
console.log(~0) // -1
console.log(~1) // -2
// and so on

Так как в JS 0 считается значением "Falsy", а любое другое число, кроме NaN, является значением "Truthy", наличие ~zepto.qsa(parent, selector).indexOf(element) вернет 0, если элемент НЕ найден, и, следовательно, поток может иметь значение "Falsy". "значение в коде:

var isFound = ~zepto.qsa(parent, selector).indexOf(element);

if (isFound) {
  // do something
}

Однако в этом случае я бы ожидал, что методы zepto вернут настоящее логическое значение, потому что это метод API. В этом случае я бы предпочел использовать просто:

match = zepto.qsa(parent, selector).indexOf(element) > -1;

Or

match = !!~zepto.qsa(parent, selector).indexOf(element);

Двойной ! используется для правильного логического представления: если indexOf возвращает -1, ~ преобразует его в 0, затем первый ! в true, а вторые в false, это логическое значение, которое мы ожидаем для "не найдено" .

Побитовое НЕ также используется для некоторых других трюков, таких как этот:

var words = ["a", "b", "c", "b", "b"];
var frequency = words.reduce(function(freq, word) {
    freq[word] = -~freq[word];
    return freq;
}, {})

Этот код возвращает объект типа {a:1, b:3, c:1}; в основном он подсчитывает частоту одного и того же строкового значения в массиве. Здесь побитовое НЕ используется с Унарный оператор отрицания, чтобы иметь инкрементный счетчик: так, если freq[word] равно undefined — потому что этого слова еще нет в «словаре» — тогда ~undefined равно -1, а при унарном отрицании становится 1. В следующий раз у нас будет -~1 и, следовательно, - -2, поэтому 2; тогда -~2 будет 3 и так далее.

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

Но они определенно заслуживают того, чтобы о них знали.

person ZER0    schedule 12.04.2013