Що !! (не) оператор у JavaScript?


3104

Я бачив деякий код , який , здається, використовувати оператор не визнати, у вигляді двох знаків оклику, наприклад , так: !!. Може хтось скажіть, будь ласка, що робить цей оператор?

Контекст, в якому я це бачив,

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

944
Запам’ятайте це за допомогою «удар, баг ти булевий»
Гас

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

73
!! не є оператором. Це просто! оператор двічі.
Vivek

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).
матовий

Відповіді:


2744

Перетворює Objectна boolean. Якби це було falsey (наприклад 0, null, undefinedі т.д.), то це буде false, в іншому випадку true.

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

Отже, !!це не оператор, це просто !оператор двічі.

Приклад реального світу "Тестова версія IE":

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
Простий спосіб описати це: булевий (5) === !! 5; Такий же кастинг, менше символів.
Міхей Снайдер

39
Це використовується для конвертації правдоподібних значень у булеві істинні, а фальшиві значення також булеві помилкові.
thetoolman

13
@Micah Snyder будьте обережні, що в JavaScript краще використовувати булеві примітиви, а не створювати об'єкти, які містять булеві нові Boolean (). Ось приклад, щоб побачити різницю: jsfiddle.net/eekbu
victorvartan

4
Наскільки я знаю, цей шаблон вибуху не є корисним всередині a if (… _ висловлювання; лише у зворотному операторі функції, яка повинна повернути булеву форму.
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
!! false = false. !! 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.
філ

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()висловлювання вже викидає вираз булевим, явне передавання значення повернення функції тестування на boolean є зайвим - оскільки "правдивість" === вірно, наскільки if()твердження йде в будь-якому випадку. Або я пропускаю сценарій, коли ви ПОТРІБНУєтесь істинним виразом, щоб насправді бути булевим true?
Том Ожер

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

103

!!перетворює значення праворуч від нього в його еквівалентне булеве значення. (Подумайте, як убогий спосіб "кастингу типу"). Її наміром зазвичай є донести до читача, що код не байдуже, яке значення в змінній, а яке це значення "істина" .


4
Або у випадку булевого значення праворуч нічого не робить.
Даніель А. Білий

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

Але в чому сенс? Якщо я роблю if(0){...Javascript, уже знаю, що це помилково. Чому краще сказати if(!!0){...?
CodyBugstein

справа в змінних, які, можливо, ви не знаєте її вмісту; якщо це може бути ціле число або рядок, об'єкт або null, не визначено тощо. Це простий спосіб перевірити існування.
mix3d

71

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

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

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

Але тоді ви можете зіткнутися з проблемами з instanceof. новий Boolean (1) instanceof Object -> true !! 1 instanceof Object -> false
Seamus

13
ні, ви не можете: зауважте, що функції конструктора викликаються без new- як прямо сказано у моїй відповіді
Крістоф

2
фантастично! Це корисно для невеликого злому, коли вам потрібно оцінити рядки з "0" як хибні, а не істинні. (тобто при зчитуванні значень з вибору, тому що вони читаються як String). Отже, якщо ви хочете вважати "0" негативним (булева помилка), асумінг x="0"просто робити: x=!!+x; //falseщо таке саме Boolean(Number(x))число (або + х) перетворює рядок "0" в 0, який НЕ оцінюється в хибний, а потім булевий (!! x) кидає його безпосередньо в булі. Простенька!
DiegoDD

2
@DiegoDD чому б ти вибрав !!+xvs 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колекції.


EDIT 24 жовтня 2017 р., 6 лютого 19 р.:

Бібліотеки сторонніх організацій, які очікують явних булевих значень

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

Наприклад, False in JSX (React) має особливе значення, яке не викликається простою помилковістю. Якщо ви спробували повернути щось подібне у своєму JSX, очікуючи int in 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, які примушують 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; він повинен бути сильно набраним булевим. Це означає, що iff 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

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

Корова без коментарів ускладнює вирішення ваших проблем! Дайте мені знати, що виглядає погано, і я буду радий вирішити це.
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

! "boolean not", який по суті набирає значення "enable" до його булевої протилежності. Другий ! перевертає це значення. Отже, !!enableозначає "не вмикати", надаючи вам значення enableяк булева.


18

Думаю, варто згадати, що умова в поєднанні з логічним AND / OR не поверне булеве значення, але останній успіх або перший збій у разі && та першого успіху або останнього відмови у випадку || стану ланцюга.

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

The !!Конструкція являє собою простий спосіб перетворити будь-який вираз JavaScript в його булевої еквівалент.

Наприклад: !!"he shot me down" === trueі !!0 === false.


2
Дуже близьке до важливого розрізнення. Ключовим є те, що 0 === falseнеправдиво і !!0 === falseє правдою.
ruffin

14

Це не один оператор, це два. Це еквівалентно наступним і є швидким способом надати значення булевим.

val.enabled = !(!enable);

10

Я підозрюю, що це залишок C ++, де люди перекривають! оператор, але не оператор bool.

Тож, щоб отримати негативну (або позитивну) відповідь у такому випадку, вам спочатку потрібно скористатися! Оператор отримати булевий, але якщо ви хочете перевірити позитивний випадок, скористайтеся !!


10

Оператори ifі whileоператори і ?оператор використовують значення істинності, щоб визначити, яку гілку коду потрібно запустити. Наприклад, нульові та NaN-числа та порожній рядок помилкові, але інші числа та рядки - істинні. Об'єкти істинні, але не визначені значення і 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або невизначене значення, наприклад виявлення функцій браузера.

Ще одне використання, про яке я згадував у відповіді про відповідного !!оператора C , - це інструменти "ворсинки", які шукають загальні друкарські помилки та діагностику друку. Наприклад, і в 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виконується логічний AND (вірно, якщо обидві сторони є істинними), і a & bвиконує побітне AND. 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 ;)

Природно, це все те саме, що просто вводити !! деякіТінг, але додані дужки можуть допомогти зробити це більш зрозумілим.


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 є ті, що називаються значеннями "truthy" та "falsey", є вирази, які при оцінці в інших виразах приведуть до справжнього або хибного стану, навіть якщо значення чи вираз, що досліджується, не є фактично trueабо false.

Наприклад:

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

Якщо цей елемент насправді існує, вираз буде оцінено як істинне, і блок коду буде виконаний.

Однак:

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

... НЕ призведе до справжнього стану, і блок коду не буде виконуватися, навіть якщо елемент існує.

Чому? Тому що document.getElementById()це "truthy" вираз, який буде оцінено як істинне в цьому if()твердженні, але воно не є фактичним булевим значенням true.

Подвійне "не" в цьому випадку досить просте. Це просто два notспини назад.

Перший просто "перевертає" значення "truthy" або "falsey", що призводить до фактичного булевого типу, а потім другий "повертає" його знову до початкового стану, але тепер у фактичне булеве значення. Таким чином ви маєте послідовність:

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 поверне перше значення фальси, яке воно знайде - і це може бути передано до заяви if і т.д. Так, якщо b.foo не визначено, воно повернеться невизначеним і пропустить b.foo.barзаяву, і ми не отримаємо помилка.

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

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 буде помилковим і ще один! це було б правдою

якщо 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.