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

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

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

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

30 ответов


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

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

так !! не является оператором, это просто


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

! is не. Так что !true и false и !false is true. !0 is 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);

!!expr возвращает логическое значение (true или false) в зависимости от truthiness выражения. Это имеет больше смысла при использовании на non-boolean типах. Рассмотрим эти примеры, особенно 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!

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

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


в теории:

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

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

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


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

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

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


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


на практике:

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

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

некоторые из вас, вероятно, заметили, что в этом конкретном примере можно просто проверить свойство, используя slightly более performant средства проверки, если объект в вопросе и свойства. Есть два способа сделать это:

// 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 С не-boolean значение, возможно, значение undefined действительно, с помощью !!. Надеюсь, это до смешного прояснит ситуацию.


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


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

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

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

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

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

просто литье :(

что есть...

  • 0 === false is false.
  • !!0 === false is true.

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

посмотреть "== и != "from JSLint-это (Примечание: Крокфорд немного перемещает свой сайт; эта ссылка может умереть в какой-то момент) немного о том, почему:

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

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

просто сказать
(foo)

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

сказать
(!foo)

обратите внимание, что есть некоторые сложным делам где логическое значение будет приведено к числу (true превращается в 1 и false to 0) когда сравнивая логический ряд. В этом случае !! может быть умственно полезным. Хотя, опять же,это случаи, когда вы сравниваете не-boolean с жестко типизированным boolean, что является, imo, серьезной ошибкой. 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());

из-за некоторые исторические окна jive, это выведет -1 в a окно сообщения! Попробуйте в cmd.exe подскажите и посмотрите! Но!--25--> по-прежнему дает 0 или WScript false. отвернуться. Это отвратительно.

сравнение truthiness :)

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

притворяться, что у нас есть myVar1 = 0; и myVar2 = undefined;.

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

таким образом, единственное место, где вам действительно нужно использовать "булевые переменные", было бы, если бы у вас была ситуация, когда вы проверяете, имеют ли обе переменные то же самое truthiness, верно? То есть, использовать !! если вам нужно увидеть, если два vars являются как истина или как ложь (или нет), то есть равной (или нет) 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:

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

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

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

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

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

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

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

  • я более комфортно falsiness обращения с троичным --
    {messageCount ? <div>You have messages!</div> : false}

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

но если вы видите странные 0в оказанных JSX, думаю, потерять управление ложь.


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

true === !!10

false === !!0

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


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


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


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

var foo = "Hello World!";

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

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


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

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

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

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


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

val.enabled = !(!enable);

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

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


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

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

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

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

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

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

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

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

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

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

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


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


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

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

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


!!x Это сокращение от Boolean(x)

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


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

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

var zero = 0;

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

!zero; //true

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

по сути, !! убедитесь, что мы получаем значение boolean, а не falsy, truthy или string и т. д...

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

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

вот фрагмент кода из 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 был assinged неопределенным, то !requestAnimationFrame будет правдой и еще одним ! это было бы ложью!--4-->


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

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

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

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

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

вместо 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

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 is false и !!a is true.


используйте логический оператор not два раза
это значит !true= false
и !!true = true


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

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

!! аналогично с помощью логический конструктор, или, возможно, больше нравится Булеву функцию.

console.log(Boolean(null)); // Preffered over the Boolean object

console.log(new Boolean(null).valueOf()); // Not recommended for coverting non-boolean values

console.log(!!null); // A hacky way to omit calling the Boolean function, but essentially does the same thing. 


// The context you saw earlier (your example)
var vertical;

function Example(vertical)
{
        this.vertical = vertical !== undefined ? !!vertical : 
        this.vertical; 
        // Let's break it down: If vertical is strictly not undefined, return the boolean value of vertical and set it to this.vertical. If not, don't set a value for this.vertical (just ignore it and set it back to what it was before; in this case, nothing).   

        return this.vertical;
}

console.log( "\n---------------------" )

// vertical is currently undefined

console.log(new Example(vertical).vertical); // The falsey or truthy value of this.vertical
console.log(!!new Example(vertical).vertical); // Coerced value of this.vertical

vertical = 12.5; // set vertical to 12.5, a truthy value.
console.log(new Example(vertical).vertical); // The falsey or truthy value of this.vertical which happens to be true anyway
console.log(!!new Example(vertical).vertical); // Coerced value of this.vertical

vertical = -0; // set vertical to -0, a falsey value.
console.log(new Example(vertical).vertical); // The falsey or truthy value of this.vertical which happens to be false either way
console.log(!!new Example(vertical).vertical); // Coerced value of this.vertical

Falsey values в javascript принуждение to false и значения истина принуждение to правда. значения Falsey и truthy также могут использоваться в if заявления и будет по существу "сопоставляться" с их соответствующим булевым значением. Однако вам, вероятно, не придется часто использовать правильные логические значения, поскольку они в основном отличаются по выходу (возвращаемым значениям).

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


почему и как это работает

чтобы быть кратким, это выглядит примерно так: ! ( !null ). Принимая во внимание, что null is falsey, так что !null будет правда. Тогда !true будет false и это было по существу инвертировать обратно к чему это было раньше, только в этот раз в качестве правильное логическое значение (или даже наоборот С значения истина как {} или 1).


возвращаясь к вашему примеру

в целом, контекст, который вы видели, просто настраивает this.vertical в зависимости от того или нет vertical определено, и если да, то будет установлено результирующее логическое значение вертикали, иначе оно не изменится. Другими словами, если vertical определена; this.vertical будет присвоено логическое значение, в противном случае, оно останется прежним. Я думаю, что само по себе является примером того, как можно использовать !!, и что он делает.


Вертикальный Пример Ввода-Вывода

запустите этот пример и поиграйте с вертикальным значением на входе. Посмотрите, к чему приводит результат, чтобы вы могли полностью понять код своего контекста. Во входных данных введите любое допустимое значение javascript. не забудьте включить цитаты, Если вы тестируете строку. не возражайте против CSS и HTML-кода слишком много, просто запустите этот фрагмент и поиграйте с ним. Однако, возможно, вы захотите взглянуть на код javascript, не связанный с DOM (использование конструктора примера и вертикальной переменной).

var vertical = document.getElementById("vertical");
var p = document.getElementById("result");

function Example(vertical)
{
        this.vertical = vertical !== undefined ? !!vertical : 
        this.vertical;   

        return this.vertical;
}

document.getElementById("run").onclick = function()
{

  p.innerHTML = !!( new Example(eval(vertical.value)).vertical );
  
}
input
{
  text-align: center;
  width: 5em;
} 

button 
{
  margin: 15.5px;
  width: 14em;
  height: 3.4em;
  color: blue;
}

var 
{
  color: purple;
}

p {
  margin: 15px;
}

span.comment {
  color: brown;
}
<!--Vertical I/O Example-->
<h4>Vertical Example</h4>
<code id="code"><var class="var">var</var> vertical = <input type="text" id="vertical" maxlength="9" />; <span class="comment">// enter any valid javascript value</span></code>
<br />
<button id="run">Run</button>
<p id="result">...</p>

это заставляет все вещи boolean.

например:

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