Что это!! (не) оператор в JavaScript?

Я видел код, который, как представляется, использует оператор, который я не распознаю в виде двух восклицательных знаков, например: !!. Может кто-нибудь, пожалуйста, скажите мне, что делает этот оператор?

Контекст, в котором я видел это, был

this.vertical = vertical !== undefined ? !!vertical : this.vertical;

Ответ 1

Принуждение oObject к логическому. Если это было false (например, 0, null, undefined и т.д.), Это будет false, в противном случае - true.

!oObject  //Inverted boolean
!!oObject //Non inverted boolean so true boolean representation

Так !! это не оператор, это просто ! оператор дважды.

Пример из реальной жизни "Test IE version":

let isIE8 = false;  
isIE8 = !! navigator.userAgent.match(/MSIE 8.0/);  
console.log(isIE8); // returns true or false 

Если вы ⇒

console.log(navigator.userAgent.match(/MSIE 8.0/));  
// returns either an Array or null  

но если вы ⇒

console.log(!!navigator.userAgent.match(/MSIE 8.0/));  
// returns either true or false

Ответ 2

Это ужасно неясный способ сделать преобразование типа.

! НЕ. Итак, !true - false, а !false - true. !0 - true, а !1 - false.

Итак, вы преобразовываете значение в логическое, затем инвертируете его, а затем снова инвертируете.

// Maximum Obscurity:
val.enabled = !!userId;

// Partial Obscurity:
val.enabled = (userId != 0) ? true : false;

// And finally, much easier to understand:
val.enabled = (userId != 0);

Ответ 3

!!expr возвращает логическое значение (true или false) в зависимости от правдоподобия выражения. Это имеет смысл при использовании в небулевых типах. Рассмотрим эти примеры, особенно третий пример и далее:

          !!false === false
           !!true === true

              !!0 === false
!!parseInt("foo") === false // NaN is falsy
              !!1 === true
             !!-1 === true  // -1 is truthy

             !!"" === false // empty string is falsy
          !!"foo" === true  // non-empty string is truthy
        !!"false" === true  // ...even if it contains a falsy value

     !!window.foo === false // undefined is falsy
           !!null === false // null is falsy

             !!{} === true  // an (empty) object is truthy
             !![] === true  // an (empty) array is truthy; PHP programmers beware!

Ответ 4

Brew некоторый чай:

!! не является оператором. Это двойное использование ! - это логический оператор "не".


Теоретически:

! определяет истинность того, что не является значением:

  • Истина заключается в том, что false не true (поэтому результаты !false в true)

  • Истина заключается в том, что true не false (что почему !true результаты в false)


!! определяет "истину" того, чего нет:

  • Истина заключается в том, что true не является true (поэтому !!true приводит к true)

  • Истина заключается в том, что false не является false (поэтому !!false приводит к false)


То, что мы хотим определить при сравнении, - это "правда" о значении ссылки, а не значение самой ссылки. Существует прецедент, где нам может понадобиться знать правду о значении, даже если мы ожидаем, что значение будет false (или falsey), или если мы ожидаем, что значение не будет typeof boolean.


На практике:

Рассмотрим краткую функцию, которая обнаруживает функциональные возможности (и в этом случае совместимость с платформой) с помощью динамического ввода (он же "утка" ). Мы хотим написать функцию, которая возвращает true, если браузер пользователя поддерживает элемент HTML5 <audio>, но мы не хотим, чтобы функция выдавала ошибку, если <audio> - undefined; и мы не хотим использовать try ... catch для обработки любых возможных ошибок (потому что они грубые); а также мы не хотим использовать проверку внутри функции, которая не будет постоянно показывать правду об этой функции (например, document.createElement('audio') все равно будет создавать элемент с именем <audio>, даже если HTML5 <audio> не поддерживается).


Вот три подхода:

// this won't tell us anything about HTML5 `<audio>` as a feature
var foo = function(tag, atr) { return document.createElement(tag)[atr]; }

// this won't return true if the feature is detected (although it works just fine)
var bar = function(tag, atr) { return !document.createElement(tag)[atr]; }

// this is the concise, feature-detecting solution we want
var baz = function(tag, atr) { return !!document.createElement(tag)[atr]; }

foo('audio', 'preload'); // returns "auto"
bar('audio', 'preload'); // returns false
baz('audio', 'preload'); // returns true

Каждая функция принимает аргумент для <tag> и attribute для поиска, но каждый из них возвращает разные значения в зависимости от того, что определяют сравнения.

Но подождите, еще больше!

Некоторые из вас, вероятно, заметили, что в этом конкретном примере можно просто проверить свойство, используя немного более эффективный средство проверки, имеет ли объект, о котором идет речь, свойство. Существует два способа сделать это:

// the native `hasOwnProperty` method
var qux = function(tag, atr) { return document.createElement(tag).hasOwnProperty(atr); }

// the `in` operator
var quux = function(tag, atr) { return atr in document.createElement(tag); }

qux('audio', 'preload');  // returns true
quux('audio', 'preload'); // returns true

Мы отвлекаемся...

Как бы редко ни возникали эти ситуации, может существовать несколько сценариев, в которых наиболее сжатые, наиболее эффективные и, следовательно, наиболее предпочтительные способы получения true из небулевого значения, возможно undefined, действительно, используют !!. Надеюсь, это смехотворно очистит его.

Ответ 5

!! преобразует значение справа от него в эквивалентное булево значение. (Подумайте, что у него плохой способ "литья" ). Его намерение, как правило, донести до читателя, что код не заботится о том, какое значение находится в переменной, но что это "true" value.

Ответ 6

!!foo дважды применяет оператор унарного оператора и используется для приведения к логическому типу, аналогичного использованию унарного плюса +foo, для приведения в число и объединения пустой строки ''+foo для перевода в строку.

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

Boolean(foo) === !!foo
Number(foo)  === +foo
String(foo)  === ''+foo

Ответ 7

Так много ответов делают половину работы. Да, !!X можно прочитать как "истинность X [представлена как логическое значение]". Но !! На самом деле, это не так важно для выяснения, является ли единственная переменная (или даже если много переменных) истинной или ложной. !!myVar === true - это то же самое, что и myVar. Сравнение !!X с "настоящим" логическим значением не очень полезно.

Что вы получаете с !! это способность проверять достоверность множества переменных друг против друга повторяемым, стандартизированным (и дружественным JSLint) способом.

Просто кастинг :(

То есть...

  • 0 === false - это false.
  • !!0 === false это true.

Выше не очень полезно. if (!0) дает вам те же результаты, что и if (!!0 === false). Я не могу придумать хорошего случая для приведения переменной к логическому, а затем сравнения с "истинным" логическим значением.

См. "== и! =" В направлениях JSLint (примечание: Крокфорд немного перемещает свой сайт; в какой-то момент эта ссылка может умереть), чтобы узнать, почему:

Операторы == и! = Выполняют приведение типов перед сравнением. Это плохо, потому что это заставляет '\ t\r\n' == 0 быть верным. Это может маскировать ошибки типа. JSLint не может надежно определить, правильно ли используется ==, поэтому лучше вообще не использовать == и! = И всегда использовать вместо этого более надежные операторы === и! ==.

Если вас волнует только то, что значение является правдивым или ложным, используйте короткую форму. Вместо
(foo != 0)

просто скажи
(foo)

и вместо
(foo == 0)

сказать
(!foo)

Обратите внимание, что есть некоторые неинтуитивные случаи, когда логическое значение будет приведено к числу (true приведено к 1 и false к 0) при сравнении логического значения с числом. В этом случае !! может быть психически полезным. Хотя, опять же, это те случаи, когда вы сравниваете не-булево значение со строго типизированным логическим значением, что, на мой взгляд, является серьезной ошибкой. if (-1) все еще путь сюда.

╔═══════════════════════════════════════╦═══════════════════╦═══════════╗
║               Original                ║    Equivalent     ║  Result   ║
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
║ if (-1 == true) console.log("spam")   ║ if (-1 == 1)      ║ undefined ║
║ if (-1 == false) console.log("spam")  ║ if (-1 == 0)      ║ undefined ║
║   Order doesn't matter...             ║                   ║           ║
║ if (true == -1) console.log("spam")   ║ if (1 == -1)      ║ undefined ║
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
║ if (!!-1 == true) console.log("spam") ║ if (true == true) ║ spam      ║ better
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
║ if (-1) console.log("spam")           ║ if (truthy)       ║ spam      ║ still best
╚═══════════════════════════════════════╩═══════════════════╩═══════════╝

И все становится еще безумнее в зависимости от вашего двигателя. WScript, например, выигрывает приз.

function test()
{
    return (1 === 1);
}
WScript.echo(test());

Из-за некоторого исторического джайва Windows это выведет -1 в окне сообщения! Попробуйте в командной строке cmd.exe и посмотрите! Но WScript.echo(-1 == test()) прежнему выдает 0 или WScript false. Отвернись. Это отвратительно.

Сравнивая правдивость :)

Но что, если у меня есть два значения, которые мне нужно проверить на одинаковую истинность/ложность?

Притворимся, что у нас myVar1 = 0; и myVar2 = undefined; ,

  • myVar1 === myVar2 равен 0 === undefined и явно ложен.
  • !!myVar1 === !!myVar2 is !!0 === !!undefined и это правда! Та же самая правдивость! (В этом случае оба "имеют правдивую ложь".)

Таким образом, единственное место, где вам действительно нужно использовать "переменные логического преобразования", было бы, если бы у вас была ситуация, когда вы проверяете, имеют ли обе переменные одинаковую истинность, верно? То есть пользуйтесь !! если вам нужно увидеть, являются ли две переменные правдивыми или ложными (или нет), то есть равными (или нет) правдивостью.

Я не могу придумать отличный, не надуманный сценарий использования для этого случая. Может быть, у вас есть "связанные" поля в форме?

if (!!customerInput.spouseName !== !!customerInput.spouseAge ) {
    errorObjects.spouse = "Please either enter a valid name AND age " 
        + "for your spouse or leave all spouse fields blank.";
}

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


РЕДАКТИРОВАТЬ 24 октября 2017 г., 6 февраля 19:

Сторонние библиотеки, которые ожидают явных логических значений

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

Например, False в JSX (React) имеет особое значение, которое не вызывается простой ложью. Если вы попытались вернуть что-то вроде следующего в ваш JSX, ожидая int в messageCount...

{messageCount && <div>You have messages!</div>}

... вы можете быть удивлены, увидев, что React отображает 0 когда у вас есть ноль сообщений. Вы должны явно вернуть false, чтобы JSX не отображал. Вышеприведенный оператор возвращает 0, что JSX успешно отображает, как и должно. Он не может сказать, что у вас не было Count: {messageCount && <div>Get your count to zero!</div>} (или что-то менее надуманное).

  • Одно из исправлений касается bangbang, который приводит 0 к !!0, что false:
    {!!messageCount && <div>You have messages!</div>}

  • Документы JSX предполагают, что вы должны быть более явными, писать код с комментированием и использовать сравнение для принудительной логической обработки.
    {messageCount > 0 && <div>You have messages!</div>}

  • Мне удобнее справляться с ложностью с тройной -
    {messageCount? <div>You have messages!</div>: false}

То же самое в Typescript: если у вас есть функция, которая возвращает логическое значение (или вы присваиваете значение логической переменной), вы [обычно] не можете вернуть/присвоить логическое значение-y; это должен быть строго типизированный логический тип. Это означает, что если myObject строго типизирован, return !myObject; работает для функции, возвращающей логическое значение, но return myObject; не делает. Вы должны return !!myObject чтобы соответствовать ожиданиям Typescript.

Исключение для Typescript? Если myObject был any, вы вернулись в JavaScript Wild West и можете вернуть его без !! , даже если ваш тип возвращаемого значения является логическим.

Имейте в виду, что это соглашения JSX и Typescript, а не присущие JavaScript.

Но если вы видите странный 0 в вашем рендеринге JSX, подумайте об управлении фальшивкой.

Ответ 8

Это просто логический оператор NOT, дважды - он используется для преобразования чего-то в boolean, например:

true === !!10

false === !!0

Ответ 9

Он преобразует суффикс в булево значение.

Ответ 10

Это двойная операция not. Первый ! преобразует значение в boolean и инвертирует его логическое значение. Второй ! инвертирует возвращаемое логическое значение.

Ответ 11

Он моделирует поведение функции Boolean() casting. Первый NOT возвращает логическое значение независимо от того, какой операнд ему задан. Второй NOT отрицает значение Boolean, и поэтому дает true логическое значение переменной. Конечный результат такой же, как при использовании функции Boolean() для значения.

Ответ 12

Кажется, что оператор !! приводит к двойному отрицанию.

var foo = "Hello World!";

!foo // Result: false
!!foo // Result: true

Ответ 13

! "boolean not", который, по существу, выводит значение "enable" в его логическую противоположность. Второй! переворачивает это значение. Таким образом, !!enable означает "не включить", что дает значение enable как логическое.

Ответ 14

Я думаю, стоит упомянуть, что условие, объединенное с логическим И/ИЛИ, не будет возвращать логическое значение, но последний успех или первый сбой в случае && а также первый успех или последний провал в случае || цепи условий.

res = (1 && 2); // res is 2
res = (true && alert) // res is function alert()
res = ('foo' || alert) // res is 'foo'

Чтобы применить условие к истинному булевскому литералу, мы можем использовать двойное отрицание:

res = !!(1 && 2); // res is true
res = !!(true && alert) // res is true
res = !!('foo' || alert) // res is true

Ответ 15

Конструкция !! - это простой способ превратить любое выражение JavaScript в его булевский эквивалент.

Например: !!"he shot me down" === true и !!0 === false.

Ответ 16

Это не один оператор, это два. Это эквивалентно следующему и является быстрым способом приведения значения в значение boolean.

val.enabled = !(!enable);

Ответ 17

!! это NOT использует операцию дважды вместе ! преобразовать значение в boolean и обратить его, вот простой пример, чтобы увидеть, как !! работает:

Во-первых, место у вас есть:

var zero = 0;

Затем вы делаете !0, оно будет преобразовано в логическое значение и будет оценено как true, потому что 0 является falsy, поэтому вы получаете обратное значение и преобразуете в логическое значение, поэтому оно оценивается как true.

!zero; //true

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

В основном, !! убедитесь, что мы получаем логическое значение, а не ложное, правдивое или строковое и т.д.

Так что это похоже на использование Boolean функции в javascript, но простой и короткий способ преобразования значения в логическое значение:

var zero = 0;
!!zero; //false

Ответ 18

Операторы if и while и оператор ? используют значения истинности, чтобы определить, какую ветвь кода запускать. Например, номера нулей и NaN и пустая строка являются ложными, но другие числа и строки являются истинными. Объекты истинны, но значение undefined и null являются ложными.

Оператор двойного отрицания !! вычисляет значение истинности значения. Это фактически два оператора, где !!x означает !(!x) и ведет себя следующим образом:

  • Если x является ложным значением, !x - true, а !!x - false.
  • Если x - истинное значение, !x - false, а !!x - true.

При использовании на верхнем уровне булевого контекста (if, while или ?) оператор !! поведенчески не работает. Например, if (x) и if (!!x) означают одно и то же.

Практическое использование

Однако он имеет несколько практических применений.

Одно использование заключается в том, чтобы с легкостью сжать объект до его значения истинности, чтобы ваш код не содержал ссылку на большой объект и сохранял его. Присвоение переменной !!some_big_object вместо some_big_object позволяет перейти к сборщику мусора. Это полезно для случаев, которые создают либо объект, либо ложное значение, такое как null или значение undefined, например обнаружение функции браузера.

Другое использование, о котором я упомянул в ответе о C-соответствующем операторе !!, - это инструменты "lint", которые ищут общие опечатки и диагностику печати. Например, как в C, так и в JavaScript несколько общих опечаток для булевых операций производят другие поведения, выход которых не совсем как Boolean:

  • if (a = b) - это присвоение, за которым следует использование значения истины b; if (a == b) - сравнение равенства.
  • if (a & b) является поразрядным И; if (a && b) является логическим И. 2 & 5 - 0 (ложное значение); 2 && 5 истинно.

Оператор !! заверяет инструмент lint, что то, что вы написали, означает то, что вы имели в виду: выполните эту операцию, затем возьмите истинное значение результата.

Третье использование - создание логического XOR и логического XNOR. В C и JavaScript a && b выполняет логическое И (true, если обе стороны истинны), а a & b выполняет побитовое И. a || b выполняет логическое ИЛИ (true, если хотя бы один из них истинно), а a | b выполняет побитовое ИЛИ. Там побитовое XOR (исключающее ИЛИ) как a ^ b, но нет встроенного оператора для логического XOR (true, если точно одна сторона является истиной). Например, вы можете разрешить пользователю вводить текст только в одном из двух полей. Что вы можете сделать, так это преобразовать их в значение истины и сравнить их: !!x !== !!y.

Ответ 19

Я подозреваю, что это осталось от С++, где люди переопределяют! оператора, но не оператора bool.

Итак, чтобы получить отрицательный (или положительный) ответ, в этом случае вам сначала нужно будет использовать! оператор, чтобы получить логическое значение, но если вы хотите проверить положительный случай, используйте!!.

Ответ 20

Двойное булево отрицание. Часто используется для проверки значения undefined.

Ответ 21

Тонны замечательных ответов здесь, но если вы зачитали это далеко, это помогло мне "получить". Откройте консоль в Chrome (и т.д.) И начните вводить:

!(!(1))
!(!(0))
!(!('truthy')) 
!(!(null))
!(!(''))
!(!(undefined))
!(!(new Object())
!(!({}))
woo = 'hoo'
!(!(woo))
...etc, etc, until the light goes on ;)

Естественно, это все равно, что просто набирать!! someThing, но добавленные скобки могут помочь сделать его более понятным.

Ответ 22

!!x является сокращением для Boolean(x)

Первый удар заставляет js-двигатель запускать Boolean(x), но также имеет побочный эффект инвертирования значения. Таким образом, второй удар отменяет побочный эффект.

Ответ 23

Это заставляет все вещи булевать.

Например:

console.log(undefined); // -> undefined
console.log(!undefined); // -> true
console.log(!!undefined); // -> false

console.log('abc'); // -> abc
console.log(!'abc'); // -> false
console.log(!!'abc'); // -> true

console.log(0 === false); // -> undefined
console.log(!0 === false); // -> false
console.log(!!0 === false); // -> true

Ответ 24

вот фрагмент кода из angular js

var requestAnimationFrame = $window.requestAnimationFrame ||
                                $window.webkitRequestAnimationFrame ||
                                $window.mozRequestAnimationFrame;

 var rafSupported = !!requestAnimationFrame;

их намерение состоит в том, чтобы установить rafSupported в true или false на основе доступности функции в requestAnimationFrame

это может быть достигнуто путем проверки следующим образом:

if(typeof  requestAnimationFrame === 'function')
rafSupported =true;
else
rafSupported =false;

можно использовать короткий путь!!

rafSupported = !!requestAnimationFrame ;

поэтому, если requestAnimationFrame была назначена функция  тогда ! requestAnimationFrame будет ложным и еще одним! из этого было бы верно

если requestAnimationFrame был оценен undefined, тогда ! requestAnimationFrame будет правдой и еще одним! из этого будет ложь

Ответ 25

Я просто хотел добавить, что

if(variableThing){
  // do something
}

такой же как

if(!!variableThing){
  // do something
}

Но это может быть проблемой, когда что-то не определено.

// a === undefined, b is an empty object (eg. b.asdf === undefined)
var a, b = {};

// Both of these give error a.foo is not defined etc.
// you'd see the same behavior for !!a.foo and !!b.foo.bar

a.foo 
b.foo.bar

// This works -- these return undefined

a && a.foo
b.foo && b.foo.bar
b && b.foo && b.foo.bar

Хитрость здесь в том, что цепочка && вернет первое найденное значение Falsey - и это может быть передано в оператор if и т.д. Поэтому, если b.foo не определен, он вернет undefined и пропустит оператор b.foo.bar и мы не получаем ошибок.

Вышеприведенный возврат не определен, но если у вас есть пустая строка, false, null, 0, undefined, эти значения вернутся, и как только мы встретим их в цепочке, - [] и {} оба являются "истинными", и мы продолжим вниз по так называемая цепочка && к следующему значению справа.

PS Другой способ сделать то же самое - это (b || {}).foo, потому что если b не определено, то b || {} b || {} будет {}, и вы будете получать доступ к значению в пустом объекте (без ошибок) вместо того, чтобы пытаться получить доступ к значению в пределах "неопределенного" (вызывает ошибку). Итак, (b || {}).foo - это то же самое, что b && b.foo а ((b || {}).foo || {}).bar - то же самое, что и b && b.foo && b.foo.bar.

Ответ 26

После просмотра всех этих замечательных ответов я хотел бы добавить еще одну причину использования !!. Currenty Я работаю в Angular 2-4 (TypeScript), и я хочу вернуть логическое значение false, когда мой пользователь не аутентифицирован. Если он не аутентифицирован, токена-строка будет null или "". Я могу сделать это, используя следующий блок кода:

public isAuthenticated(): boolean {
   return !!this.getToken();
}

Ответ 27

На этот вопрос был дан довольно подробный ответ, но я хотел бы добавить ответ, который, я надеюсь, будет максимально упрощенным, что придает смысл !! так просто понять, как это может быть.

Поскольку в javascript есть значения, которые называются "истинными" и "ложными" значениями, существуют выражения, которые при оценке в других выражениях приводят к условию "истина" или "ложь", даже если проверяемое значение или выражение на самом деле не является true или false.

Например:

if (document.getElementById('myElement')) {
    // code block
}

Если этот элемент действительно существует, выражение будет оцениваться как true, и будет выполнен блок кода.

Тем не мение:

if (document.getElementById('myElement') == true) {
    // code block
}

... НЕ приведет к истинному условию, и блок кода не будет выполнен, даже если элемент существует.

Зачем? Потому что document.getElementById() является "истинным" выражением, которое будет оцениваться как истинное в этом операторе if(), но не является фактическим логическим значением true.

Двойное "не" в этом случае довольно просто. Это просто двое, а not спина к спине.

Первый просто "инвертирует" истинное или ложное значение, в результате чего получается фактический логический тип, а затем второй "инвертирует" его обратно в исходное состояние, но теперь в фактическое логическое значение. Таким образом, у вас есть последовательность:

if (!!document.getElementById('myElement')) {}

а также

if (!!document.getElementById('myElement') == true) {}

ОБА вернет истину, как и ожидалось.

Ответ 28

Некоторые операторы в JavaScript выполняют неявные преобразования типов и иногда используется для преобразования типов.

Унарный оператор ! преобразует свой операнд в булев и отрицает его.

Этот факт приводит к следующей идиоме, которую вы можете увидеть в своем исходном коде:

!!x // Same as Boolean(x). Note double exclamation mark

Ответ 29

Возвращает логическое значение переменной.

Вместо этого может использоваться класс Boolean.

(пожалуйста, прочитайте описания кода)

var X = "test"; // X value is "test" as a String value
var booleanX = !!X // booleanX is `true` as a Boolean value beacuse non-empty strings evaluates as `true` in boolean
var whatIsXValueInBoolean = Boolean(X) // whatIsXValueInBoolean is `true` again
console.log(Boolean(X) === !!X) // writes `true`

А именно, Boolean(X) = !!X в использовании.

Пожалуйста, проверьте фрагмент кода ниже

let a = 0
console.log("a: ", a) // writes a value in its kind
console.log("!a: ", !a) // writes '0 is NOT true in boolean' value as boolean - So that true.In boolean 0 means false and 1 means true.
console.log("!!a: ", !!a) // writes 0 value in boolean. 0 means false.
console.log("Boolean(a): ", Boolean(a)) // equals to `!!a`
console.log("\n") // newline

a = 1
console.log("a: ", a)
console.log("!a: ", !a)
console.log("!!a: ", !!a) // writes 1 value in boolean
console.log("\n") // newline

a = ""
console.log("a: ", a)
console.log("!a: ", !a) // writes '"" is NOT true in boolean' value as boolean - So that true.In boolean empty strings, null and undefined values mean false and if there is a string it means true.
console.log("!!a: ", !!a) // writes "" value in boolean
console.log("\n") // newline

a = "test"
console.log("a: ", a) // writes a value in its kind
console.log("!a: ", !a)
console.log("!!a: ", !!a) // writes "test" value in boolean

console.log("Boolean(a) === !!a: ", Boolean(a) === !!a) // writes true

Ответ 30

a = 1;
alert(!a) // -> false : a is not not defined
alert(!!a) // -> true : a is not not defined

Для !a он проверяет, существует ли a НЕ, а !!a проверяет, определена ли переменная.

!!a совпадает с !(!a). Если a определено, a - true, !a - false, а !!a - true.