Что !! (не нет) оператор в JavaScript? - PullRequest
2723 голосов
/ 24 апреля 2009

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

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

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

Ответы [ 35 ]

2441 голосов
/ 24 апреля 2009

Принуждение oObject к логическому значению. Если это была ложь (например, 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
805 голосов
/ 10 сентября 2009

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

! - это НЕ . Таким образом, !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);
415 голосов
/ 15 мая 2012

!!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!
142 голосов
/ 23 февраля 2013

Заварить чай:

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


В теории:

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

  • Правда в том, что false не true (поэтому !false результаты в true)

  • Правда в том, что true не false (поэтому !true результаты в false)


!! определяет «истинность» значения не не:

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

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


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


На практике:

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

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

94 голосов
/ 10 сентября 2009

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

65 голосов
/ 11 сентября 2009

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

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

Boolean(foo) === !!foo
Number(foo)  === +foo
String(foo)  === ''+foo
59 голосов
/ 29 апреля 2015

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

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

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

То есть ...

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

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

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

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

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

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

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

1050 * говорят * (!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 и это правда! Та же самая правдивость! (В этом случае оба «имеют ложную правду».)

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

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

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>} (или чего-то менее надуманного).

  • Одно исправление включает в себя взрыв, который приводит 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 .

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

50 голосов
/ 24 апреля 2009

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

true === !!10

false === !!0
30 голосов
/ 10 сентября 2009

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

24 голосов
/ 10 сентября 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...