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


3110

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

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

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

946
Помните это как «взрыв, взрыв, вы булевы»
Гас,

75
Просто для записи, не делайте того, что там указано. Делайте if(vertical !== undefined) this.vertical = Boolean(vertical);- это намного чище и яснее, что происходит, не требует ненужного назначения, полностью стандартно и столь же быстро (на текущих FF и Chrome) jsperf.com/boolean-conversion-speed .
Фил Х

73
!! не оператор. Это просто! оператор дважды.
Вивек

11
Просто для записи, Boolean(5/0)это не то же самое, что!!5/0
schabluk

63
@schabluk, для записи, порядок операций является причиной !!5/0производит , Infinityа не true, как произведено Boolean(5/0). !!5/0эквивалентно (!!5)/0- aka true/0- из-за того, что !оператор имеет более высокий приоритет, чем /оператор. Если вы хотите Booleanize 5/0с использованием двойного взрыва, вам нужно будет использовать !!(5/0).
Мэтти

Ответы:


2750

Преобразует Objectв boolean. Если бы это было falsey (например 0, null, undefinedи т.д.), то это будет false, в противном случае true.

!oObject  // inverted boolean
!!oObject // non inverted boolean so true boolean representation

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

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

const 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

123
Он преобразует небулево значение в инвертированное логическое значение (например,! 5 будет ложным, так как 5 - не ложное значение в JS), а затем логическое инвертирует, так что вы получите исходное значение как логическое значение (так что !! 5 будет будь настоящим).
Чак

111
Простой способ описать это: Boolean (5) === !! 5; Тот же кастинг, меньше персонажей.
Мика Снайдер

39
Это используется для преобразования истинных значений в логическое значение true, а ложные значения слишком логические false.
thetoolman

13
@Micah Снайдер, будьте осторожны, в JavaScript лучше использовать логические примитивы, а не создавать объекты, которые содержат логические значения с новым Boolean (). Вот пример, чтобы увидеть разницу: jsfiddle.net/eekbu
victorvartan

4
Насколько я знаю, этот шаблон bang-bang бесполезен в операторе if (… _; только в операторе return функции, которая должна возвращать логическое значение.
rds

854

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

!это НЕ . Так !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);

74
!! ложь = ложь. !! true = true
cllpse

89
Неужели вариант "намного проще для понимания" действительно намного легче понять здесь? Проверка на 0 не является реальной проверкой на 0, но проверка на несколько странный список значений, которые Javascript считает равными 0. Это userId ? true : false делает более ясным, что происходит преобразование, и обрабатывает случай, когда значение userId могло быть явно установлено равнымundefined
Бен Регенспан,

54
У моего мозга нет проблем с расшифровкой !!varв Boolean(var)... и !!он быстрее (меньше инструкций для обработки) и короче, чем альтернативы.
adamJLev

7
@RickyClarkson в основном для удобства чтения, поскольку синтаксически это не требуется. Некоторые используют соглашение всегда заключать условные скобки в круглые скобки, чтобы отделить его от остальной части выражения.
Дэйв Рейджер

8
Я не согласен с этим. userId != 0верно null, NaNи undefined, но неверно для false. Если вы хотите именно такое поведение, вы, вероятно, должны быть откровенными об этом. Но даже если он работает точно так же, как !!userId, неясно, хотите ли вы, чтобы эти значения были здесь ложными, или вы просто не учли правила преобразования типов Javascript.
Philh

449

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

          !!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!

63
Стоит отметить:!!new Boolean(false) // true
Камило Мартин

43
... Но также!!Boolean(false) // false
Камило Мартин

97
new Boolean(false)является объектом, и объект является правдивым, даже если он содержит ложное значение!
Салман А

3
Да , я знаю, но учитывать тот факт , что большинство родных Конструкторов ( String, Number, Dateи т.д.) предназначены для вызываемых как функции тоже, но в этом случае результат отличается!
Камило Мартин

4
@CamiloMartin: только что понял, что new Boolean(false)возвращает objectвремя Boolean(false)возвращает примитив false . Надеюсь, это имеет смысл.
Салман А

155

Заварите немного чая:

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


В теории:

! определяет «правду» о том, что значение не является:

  • Правда в том, что falseэто не так true(вот почему и !falseприводит к true)

  • Правда в том, что trueэто не так false(вот почему и !trueприводит к false)


!!определяет «правду» о том, что значение не является :

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

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


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


На практике:

Рассмотрим краткую функцию, которая определяет функциональные возможности (и в данном случае совместимость с платформой) посредством динамической типизации (так называемая «утиная типизация»). Мы хотим написать функцию, которая возвращает, trueесли браузер пользователя поддерживает <audio>элемент HTML5 , но мы не хотим, чтобы функция выдавала ошибку, если <audio>она не определена; и мы не хотим использовать 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

Каждая функция принимает аргументы для поиска a <tag>и an 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небулева, возможно, неопределенного значения действительно является использование !!. Надеюсь, это смехотворно проясняет.


1
совершенно потрясающий ответ, но я не вижу полезности !! построить. Поскольку if()оператор уже преобразует выражение в логическое значение, явное приведение возвращаемого значения тестирующей функции к логическому является избыточным - поскольку "истинность" === истина в том, что касается if()оператора в любом случае. Или я пропускаю сценарий, в котором вам НУЖНО правдивое выражение, чтобы на самом деле быть логическим true?
Том Оджер

1
Операторы @TomAuger if()действительно приводят логические значения против значений Falsey, но говорят, что вы действительно хотите установить логический флаг для объекта - он не будет приводить его, как if()оператор. Например object.hasTheThing = !!castTheReturnValToBoolNoMatterWhat(), установил бы trueили falseвместо реального возвращаемого значения. Другим примером является , возможно , все админы idиз 0и не-админы идентификатор 1или выше. Чтобы получить, trueесли кто-то не является администратором, вы могли бы сделать person.isNotAdmin = !!admin.id. Мало случаев использования, но это сжато, когда есть.
Бенни

103

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


4
Или в случае логического значения справа, оно ничего не делает.
Дэниел А. Уайт,

3
@Daniel: по- !прежнему переворачивает значение вправо. В случае логического значения самое правое !отрицает значение, а самое левое !отрицает его еще раз. Чистый эффект состоит в том, что изменений нет, но большинство движков генерируют коды операций для двойного отрицания.
Crescent Fresh

Но какой в ​​этом смысл? Если я это сделаю, if(0){...Javascript уже знает, что это неверно. Почему лучше сказать if(!!0){...?
CodyBugstein

дело в переменных, которые вы, возможно, не знаете, их содержание; если это может быть целое число или строка, объект или ноль, неопределенный и т. д. Это простой способ проверить существование.
mix3d 22.09.16

71

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

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

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

Но тогда вы можете столкнуться с проблемами с instanceof. new Boolean (1) instanceof Object -> true !! 1 instanceof Object -> false
Симус

13
нет, вы не можете: обратите внимание, что функции конструктора вызываются без new- как явно указано в моем ответе
Кристоф

2
фантастический! Это полезно для небольшого взлома, когда вам нужно оценивать строки с «0» как false вместо true. (т.е. при чтении значений из select, потому что они читаются как String). Таким образом, если вы хотите считать «0» отрицательным (логическое значение «ложь»), то x="0"просто сделайте следующее: x=!!+x; //falseто же самое, что и Boolean(Number(x))число (или + x), преобразует строку «0» в 0, которое оценивается как ложное, а затем логическое значение (!! x) бросает его в логическое значение напрямую. Очень просто!
DiegoDD

2
@DiegoDD почему бы вы выбрали !!+xпротив x !== "0"?
Placeybordeaux

@placeybordeaux, потому что, например, вы можете преобразовать значение и присвоить его другой переменной, независимо от того, собираетесь ли вы сравнить его с чем-то другим или нет.
DiegoDD

67

Так много ответов делают половину работы. Да, !!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это !!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 Дикого Запада и может вернуть его без !!, даже если ваш тип возвращаемого значения является логическим.

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

Но если вы видите странные 0s в вашем рендеринге JSX, подумайте о ложном управлении.


Хорошее объяснение. Так бы ты сказал !! не является строго необходимым в этом примере обнаружения функции Worker ? if (!!window.Worker)
jk7

2
Нет, тебе это не понадобится. Истина и true« внешность » действуют точно так же в if. Я продолжаю пытаться, но не могу придумать причину, по которой приведение истинности к булевому значению предпочтительнее за пределами вышеупомянутого сложного случая «сравнить правдивость», за исключением читабельности, если вы повторно используете значение позже, как в qпримере с библиотекой. , Но даже тогда это ярлык с потерями информации, и я бы сказал, что каждый раз вам лучше оценивать правдивость.
Ерф

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

Прогнозы без комментариев затрудняют решение вашей проблемы! Дайте мне знать, что выглядит плохо, и я буду рад решить эту проблему.
ruffin

55

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

true === !!10

false === !!0

3
С какой стати ты это сделал? Использовать ! оператор для преобразования в логическое значение, а затем использовать === для сравнения типа? Просто примите, что у вас нет безопасности типов и выполните val> 0 или что-то в этом роде.
Даррен Кларк

43
@Darren: он не сравнивает типы; он говорит вам, каковы результаты, записывая утверждения в своем ответе.
Гонки легкости на орбите


26

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


26

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

var foo = "Hello World!";

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

23

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


20

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


18

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

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

17

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

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

var zero = 0;

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

!zero; //true

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

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

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

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

15

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

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


2
Очень близко к важному различию. Ключ в том, что 0 === falseэто ложь и !!0 === falseправда.
Ерф

14

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

val.enabled = !(!enable);

10

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

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


10

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

Оператор двойного отрицания !!вычисляет истинное значение значения. Это на самом деле два оператора, где !!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или неопределенное значение, например обнаружение функций браузера.

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

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

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

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



8

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

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

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


8

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

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


8

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

Например:

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

7

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

Поскольку 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) {}

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


7

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

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

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

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

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


Хороший вопрос - изменил мой ответ. Это происходит только на объекте, когда он вложен в три уровня глубиной, потому что, как вы сказали ({}).anything, дастundefined
Райан Тейлор

5

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

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

4

вот кусок кода от угловой 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 будет false и еще один! это было бы правдой

если бы requestAnimationFrame был определен как неопределенный, тогда! requestAnimationFrame был бы верным и еще одним! это было бы ложным


3

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

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

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

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


3

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

Вместо этого 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's 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's 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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.