3

I saw following piece of code on github.

/**
 * Filters an array of objects with multiple criteria.
 *
 * @param  {Array}  array: the array to filter
 * @param  {Object} filters: an object with the filter criteria as the property names
 * @return {Array}
 */
function multiFilter(array, filters) {
  const filterKeys = Object.keys(filters);
  // filters all elements passing the criteria
  return array.filter((item) => {
    // dynamically validate all filter criteria
    return filterKeys.every(key => !!~filters[key].indexOf(item[key]));
  });
}

I don't understand, what does !!~ do here?

PS: I know C and C++ languages and but I'm newbie with Javascript. I know about that operators but I don't understand, Why does use double negation(!!) with bitwise not(~) operator?

msc
  • 33,420
  • 29
  • 119
  • 214
  • 1
    Take the negation of a negation, which is a way to cast it to a Boolean. For some bizarre reason they've then done a bitwise negation on that. – jhpratt Jun 26 '18 at 05:54
  • It's just another way to "cast" to a boolean, not sure for what kind of reason there is the extra bitwise negation which is, to me, entirely unnecessary, unless it's somehow transforming the indexof. – briosheje Jun 26 '18 at 05:58
  • 1
    I would like to know is `!!~` faster than `!= -1`? – Terry Wei Jun 26 '18 at 06:04
  • 1
    @TerryWei: I rmb saw someone made the comparison and bitwise is slightly faster. But the amount is negligible – Isaac Jun 26 '18 at 06:06
  • use `includes()` which returns a boolean ( true or false ). if you want to know if an element is inside an array/string. No need to use this `~` as it's very hard to read and understand if anyone will ever look over your code. Just because you can use something doesn't mean you should :) – Mihai T Jun 26 '18 at 06:08
  • `!!` is superfluous, because filter expect a boolean value which is converted to, if not. – Nina Scholz Jun 26 '18 at 06:34

4 Answers4

7

indexOf will return the index 0-x if the element is found, -1 otherwise.

~ will change all the bits in the number, turning -1 to 0 (the binary represantation of -1 is 1111 1111 ...).

0 is a falsy value, all other numbers are truthy.

!! will convert a falsy value to false and a truthy value to true. It wouldn't be needed here, because every doesn't care whether it recieves a truthy value or true.

As others have mentioned, nowadays you could use includes. However, includes is newer to the JavaScript ecosystem than indexOf, so this solution would work in IE, the solution with include would not. You could still use includes in IE either by providing a polyfill or by transpiling your code.

SandroKSG
  • 86
  • 3
3

The tilde turns the resulting indexOf expression truthy if the item is found, and falsey if the item is not found. The !! then converts the result to a boolean from a number. (which is not useful at all, since every only cares about whether the result is truthy or falsey)

It's terribly unclear. It would be much better to use this instead:

return array.filter((item) => {
  // dynamically validate all filter criteria
  return filterKeys.every(key => filters[key].includes(item[key]));
});
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
1

var fruits = ["Banana", "Orange", "Apple", "Mango"];
var a = ~fruits.indexOf("Banana");
var b = !a;
var c = !!a;
console.log('a:',a);
console.log('b:',b);
console.log('c:',c);

It can be break into steps as above to trying to understand what's going on. Bitwise operator: ~ is a common way to replace the ugly 0/-1 comparison when using indexOf method. A double negation using !! will gives us a Boolean to tell whether it's found or not found

Isaac
  • 12,042
  • 16
  • 52
  • 116
0

!!~ means bitwise not ~ followed by double negation !!.

Bitwise not operates by reversing all the bits in the operand.

Harshal Patil
  • 17,838
  • 14
  • 60
  • 126