Why use double exclamation marks in an if statement?

There isn't any run-time benefit (or an objective one) whatsoever to doing this in an if statement. The evaluation performed by the if statement will yield precisely the same result as the evaluation produced by double exclamation mark. There is no difference.

Double exclamation marks is a useful expression to ensure boolean value based on truthyness. Consider, for instance:

var text = undefined;
console.log(text); // undefined
console.log(!!text); // false

// It would make sense here, because a boolean value is expected.
var isTextDefined = !!text;

// It would also affect serialization
JSON.stringify(text); // undefined (non-string)
JSON.stringify(!!text); // "false"

I suppose that this is a habit that was picked up because of the above use cases, thus always converting to boolean when wishing to address a variable's truthyness. It's easier for us (humans and programmers) to follow a rule when it's always applied. You'll either use the blinkers in your car all the time, even when there's nobody around, or it's likely that you'll occasionally (or maybe often) forget to signal when you should have.


Short answer: No, there is no reason.

In your code, it's already a boolean type, there is no need to convert it, and convert back again, you will always get the same result. Actually, if you have any boolean (true or false), when you use !! with any of them, it will be converted back to it's initial value:

console.log(!!true); // Will be always "true"
console.log(typeof !!true); // It stills a "boolean" type
console.log(!!false); // Will be always "false"
console.log(typeof !!false); // It stills a "boolean" type

Answer for edited question: Yes, it's the same. That's what if(...) actually does - it's trying to convert any type to boolean.

Here is a small test, you can play around with that and add whatever you want inside initialArr array to test, does it behave the same with if and !!:

const initialArr = [
  undefined,
  null,
  true,
  false,
  0,
  3,
  -1,
  +Infinity,
  -Infinity,
  Infinity,
  'any',
  '',
  function() { return 1 },
  {},
  { prop: 1 },
  [],
  [0],
  [0, 1]
];

function testIsTheSame(arr) {
  equolityCounter = 0;
  arr.forEach(item => {
    let ifStatement = false;
    let doubleNotStatement = !!item;
    if(item) {
      ifStatement = true;
    }

    if(ifStatement === doubleNotStatement && typeof ifStatement === typeof doubleNotStatement) {
      equolityCounter++;
    }
  });
  console.log(`Is the same: ${equolityCounter === arr.length}`);
}

testIsTheSame(initialArr);

I would say it was mostly done for code-readability. I doubt there is any significant performance nor compatibility implications (someone feel free to test this please)

But in the code-readability aspect, it would imply to me that this variable previously was not a boolean, but we want to evaluate it as one, if you add new logic concerning this variable, keep that in mind.

Although in your case its already boolean, so its 100% redundant, but I'd guess just a habit of someone for the above reasoning applied excessively, and/or seeing it elsewhere and copying that pattern without fully understanding it (short story time: in C# you can name a protected term a variable name by adding @, so var @class = "hello";, a junior dev just assumed all variable names needed @ in front of them, and coded that way. I wonder if someone assumed that an if without a comparison operator needs to have !! in front of it as a comparison operator)