Питання Що !! (не ні) оператор в JavaScript?


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

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

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

2330
2018-04-24 08:13


походження


Пам'ятайте про це "вибухом, вибухом, ви булеві" - Gus
Просто для запису, не робіть того, що там цитується. Зробіть if(vertical !== undefined) this.vertical = Boolean(vertical); - це набагато чистіше і чіткіше, що відбувається, не вимагає ніякого зайвого призначення, є цілком стандартним і настільки ж швидким (на поточних FF і Chrome) jsperf.com/boolean-conversion-speed . - Phil H
!! не є оператором. Це просто! оператор двічі - Vivek
Тільки для запису Boolean(5/0) не те ж саме, що !!5/0 - schabluk
@ шаблук, для запису порядок проведення операцій це причина !!5/0 випускає Infinity а не true, як виробляється Boolean(5/0). !!5/0 еквівалентно (!!5)/0 - a.k.a. true/0 -- внаслідок ! оператор має вищий пріоритет, ніж / оператор Якщо ви хочете зробити логіну 5/0 використовуючи подвійний вибух, потрібно використовувати !!(5/0). - matty


Відповіді:


Coerces 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 null  

але якщо ти ⇒

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

2076
2018-04-24 08:18



Він перетворює nonboolean на інвертований логічний (наприклад,! 5 буде помилковим, оскільки 5 є не-помилковим значенням у JS), а потім логічно-інвертується, тому ви отримаєте початкове значення як логічне значення (так що 5 бути правдою). - Chuck
Простий спосіб описати це: Boolean (5) === !! 5; Той же кастинг, менше символів. - Micah Snyder
Це використовується для перетворення truey значення в логічне значення true, а фальшиві значення занадто логічно помилкові. - thetoolman
@ Міка Снайдер будьте обережні, щоб у JavaScript краще використовувати булеві примітиви, а не створювати об'єкти, що вставляються в поле з новим Boolean (). Ось приклад, щоб побачити різницю: jsfiddle.net/eekbu - victorvartan
Наскільки я знаю, цей шаблон вибуху-вибуху не є корисним в команді if (... _, лише у зворотному викладі функції, яка повинна повернути логічний. - rds


Це жахливо неясний спосіб перетворення типу.

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

733
2017-09-10 17:28



!! false = false !! правда = правда - roosteronacid
(userId == 0) ? false : true; найчастіше болить мого мозку. - Andy Gaskell
Вражаюче незрозуміло .... прекрасно лаконічно на моїх очах .... - James Westgate
Чи "набагато легше зрозуміти" варіант тут набагато простіше зрозуміти? Перевірка проти 0 не є фактичною перевіркою проти 0, але перевірка на дещо дивний список значень Javascript вважає рівним 0. userId ? true : false  дає більш чітке уявлення про те, що відбувається конверсія, і обробляє ситуацію, коли значення UserId може бути явно встановлено undefined - Ben Regenspan
Мій мозок не має ніяких проблем з декодуванням !!var в Boolean(var) .. і !! це швидше (менше інструкцій для обробки) і коротше, ніж альтернативи. - adamJLev


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

376
2018-05-15 09:06



Варто відзначити: !!new Boolean(false) // true - Camilo Martin
...Але також !!Boolean(false) // false - Camilo Martin
new Boolean(false) є об'єктом, а об'єкт є правдивим, навіть якщо воно містить фальшиве значення! - Salman A
Так, я знаю, але врахуйте той факт, що більшість вітчизняних конструкторів (String, Number, Date, і т. д.) мають бути викликуваними як функції, але в цьому випадку результат є іншим! - Camilo Martin
@SalmanA Я також сподіваюсь, що для JavaScript має сенс іноді: D - Camilo Martin


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

!! не є оператором. Це подвійне використання ! - що є логічним "не" оператором.


В теорії:

! визначає "правду" того, що не має значення:

  • Правда в тому, що false не true (ось чому !false результати в true)

  • Правда в тому, що true не false (ось чому !true результати в false)


!! визначає "істину" того, що таке значення ні не:

  • Правда в тому, що true не ні  true (ось чому !!true призводить до true)

  • Правда в тому, що false не ні  false (ось чому !!false призводить до false)


Що ми хочемо визначити у порівнянні, це "правда" про значення посилання, а не вартість сама довідка. Існує випадк використання, коли ми можемо захотіти дізнатись правду про цінність, навіть якщо ми сподіваємось на це значення false (або помилково), або якщо ми очікуємо, що значення не буде типовим 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

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


130
2018-02-22 23:45



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


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


87
2017-09-10 17:26



Або у випадку булевого значення справа, він нічого не робить. - Daniel A. White
@ Даніель: ! все ще перевертає значення вправо. У випадку з булевим правильним ! занижує значення, а ліва - найбільша ! заперечує це ще раз. Чистий ефект полягає в тому, що змін не відбувається, але більшість двигунів буде генерувати op-коди для подвійного заперечення. - Crescent Fresh
Але в чому справа? Якщо я це зробив if(0){... Javascript вже знає, що це невірно. Чому краще сказати? if(!!0){...? - CodyBugstein
справа стосується змінних, які ви, можливо, не знаєте його вмісту; якщо це може бути цілим чи рядком, об'єкт або нульовий, невизначений і т. д. Це простий спосіб перевірити існування. - mix3d


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

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

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

59
2017-09-10 21:15



Але тоді ви можете зіткнутися з проблемами з exampleof. новий логічний (1) instanceof Object -> true !! 1 instanceof Object -> false - Seamus
ні, ви не можете: помітите, що функції конструктора викликаються без new - як явно сказано в моїй відповіді - Christoph
фантастичний! Це корисно для невеликого зламу, коли вам потрібно оцінити рядки з "0" як помилкові, а не істинними. (наприклад, при читанні значень вибраних, оскільки вони читаються як String). Отже, якщо ви хочете вважати "0" негативним (логічне значення - ложне), аніж x="0" просто роби: x=!!+x; //false яка така ж, як і Boolean(Number(x)) Число (або + x) перетворює рядок "0" на 0, що оцінюється як false, а потім логічне (!! x) виводить його безпосередньо до логічного. Простенька! - DiegoDD
@DiegoDD чому б ви вибрали !!+x проти x !== "0"? - placeybordeaux
@placeybordeaux, наприклад, можливо, вам доведеться перетворити значення та призначити його іншої змінної, незалежно від того, чи збираєтесь ви порівняти її з чим-небудь іншим чи ні. - DiegoDD


Багато відповідей робить половину роботи. так, !!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)

казати
(!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 року: 

Сторонні бібліотеки, які очікують явних булевих значень

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

Наприклад, Неправильний в JSX (React) має особливе значення це не спричинено простою хибністю. Якщо ви намагалися повернути щось на зразок наступного у вашому JSX, очікуєте int в messageCount...

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

... Ви можете бути здивовані, побачивши React render a 0 коли у вас є нульові повідомлення. Ви повинні явно повернути помилку, щоб 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}

Майте на увазі, що це це JSX конвенція, ні один не властивий JavaScript.

Але якщо ви бачите дивно 0s у вашому наданому JSX, думаєш, що втратите фальшиве управління.


47
2018-04-29 18:14



Гарне пояснення. Так що б ви сказали !! в цьому немає суто необхідного Виявлення робочого функцій приклад? if (!!window.Worker) - jk7
Ні, вам це не потрібно. Правдивість і true "зовнішньо" працюють точно так само в if. Я продовжую намагатися, але я не можу придумати причину, щоб віддавати перевагу відправленню правдивість до логічного значення за винятком випадку з витвором "порівняти правдивість" вище, за винятком читабельності, якщо ви знову використовуєте значення пізніше, як у q приклад бібліотеки. Але навіть тоді це ярлик із втратою інформації, і я стверджую, що ви краще оцінювати правдивість кожного разу. - ruffin
Реакція є основною причиною, з якої ми почали використовувати !! шаблон, але це буває дуже зручною і повторюваною річчю. Мені потрібно лише турбуватися про правдивість або фальшивості чогось, а не про те, що є основним типом. - Alexander Pritchard


Це просто логічний НЕ-оператор, двічі - він використовується для перетворення коду до логічного, наприклад:

true === !!10

false === !!0

44
2018-04-24 08:18



Чому б ти це робити? Використовувати ! Оператор перетворити на логічне, потім використовувати === для порівняння типу? Просто візьміть до уваги, що ви не маєте типової безпеки і не зробите val> 0 або щось. - Darren Clark
@ Даррен: Він не порівнює типи; він розповідає вам про результати, написавши твердження в його відповіді. - Lightness Races in Orbit