Хотя это и не методичное использование логического оператора в JavaScript, двойной восклицательный знак !! ("double bang") все чаще применяется разработчиками в своем коде. Попробуем углубиться в его механику и сложность использования.

Одинарный "!"

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

Рассмотрим три логических оператора, используемых в JavaScript: && - и, || - или, ! - не.

Оператор НЕ, обозначающийся восклицательным знаком ! является единственным логическим оператором в JS, который имеет важную особенность всегда вычислять булевое значение (true или false), в то время, когда операторы && и || могут возвращать не только булевые значения.

Реализация true и false

Как мы можем использовать ! в качестве логического преимущества в JS?

Все значения в JS считаются истинными, если только они не определены как ложные значения. Ложные значения в JS: false, 0, пустая строка "", null, undefined и NaN

В булевом контексте истинное значение преобразуется в true, а ложное в false.

Вот как это выглядит в действии:

!true === false  // НЕ true равно false
!false === true  // НЕ false равно true

Если абстрагироваться от работы с логическими значениями:

!(X) ? Y : Z  // Результат зависит от того, истинно ли значение X или нет

Что будет происходить в примере выше: X сначала преобразуется в логическое значение, а затем оператор ! будет отрицать (или инвертировать) это логическое значение. Таким образом, если X будет иметь ложное значение, согласно условию отработает выражение Y, а если нет - то Z.

Двойной "!!"

Такая комбинация трактуется, как НЕ НЕ и стоить понимать, что в JS оператора !! нет, это просто два одиночных !.

!!true === true  // НЕ НЕ true равно true
!!false === false  // НЕ НЕ false равно false

!!!true === false  // НЕ НЕ НЕ true равно false
!!!!true === true  // НЕ НЕ НЕ НЕ true равно true

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

Стоит ли использовать !! в реальных проектах

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

Одно из преимуществ использования !! заключается в том, чтобы сообщить что ваше решение должно возвращать только true или false. То есть когда вы смотрите на этот код и видите !!, вы точно будете знать, что результатом выражения будет булевое значение.

Один из спорных моментов в применении данной конструкции - это удобочитаемость такого кода. Второй момент - это кажущаяся дополнительная сложность, которую можно упростить, добавив немного больше кода для гибкости. Еще одна критика связана с тем, что ноль является ложным значением, поэтому многие варианты использования !! с числами вызывают дополнительные опасения.

Примеры использования двойного восклицательного знака

В разных источниках есть хорошие примеры и даже тесты скорости, которые показывают конкретные сравнения производительности при использовании !!. Вот некоторые из них, написанные в более простой и наглядной форме:

const array = [1,2];
!!array[0];  // => true
!!array[1];  // => true
!!array[2];  // => false

const obj = {
  value: 5,
  node: null
};
!!obj.value;  // => true
!!obj.node;  // => false

Представьте себе случай, когда цель функции - вернуть true или false при работе с различными примитивными типами данных. Переменным в функции могут быть назначены числа, строки, значения undefined или даже null. Согласитесь, подобная функция будет нуждается во внимательном пересмотре ее кода с применением различных условий и проверок на тип данных. Однако быстрым решением может быть применение конструкции !!:

const hardFunction = function() {
  ...
  return !!PrimitiveType;  // функция вернет true или false
}

А что, если в функции возвращается результат, зависящий от нескольких событий:

const discoDance = function() {
  ...
  return !!(this.dance().type && this.dance().moves.length > 0);
}

Либо комбинация операторов ! может использоваться для сокращения в условном выражении:

const things = function() {
  ...
  if (!!this.thing && this.otherThing < this.thing.length) {
  ...
}

Резюмируя, можно сделать вывод, что !! - это довольно логичный инструмент, о котором нужно знать и использовать с умом, осознавая, что он может вызвать мгновенную ясность у одних или замешательство у других в зависимости от того, кто смотрит на ваш код и как он написан.