Co to jest !! (nie nie) operator w JavaScript?


3103

Widziałem jakiś kod, który wydaje się używać operatora nie uznaję, w postaci dwóch wykrzykników, tak: !!. Czy ktoś może mi powiedzieć, co robi ten operator?

Kontekst, w którym to widziałem, był

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

944
Zapamiętaj to przez „huk, huk jesteś boolean”
Gus

75
Dla przypomnienia, nie rób tego, co jest tam cytowane. Zrób if(vertical !== undefined) this.vertical = Boolean(vertical);- jest o wiele czystsze i bardziej zrozumiałe, co się dzieje, nie wymaga niepotrzebnego przypisania, jest całkowicie standardowe i jest równie szybkie (w obecnych wersjach FF i Chrome) jsperf.com/boolean-conversion-speed .
Phil H

73
!! nie jest operatorem. To tylko! operator dwukrotnie.
Vivek

11
Dla Boolean(5/0)!!5/0
przypomnienia

63
@schabluk, dla przypomnienia, kolejność operacji jest powód !!5/0produkuje Infinityzamiast true, jak produkowane przez Boolean(5/0). !!5/0jest równoważne (!!5)/0- aka true/0- ponieważ !operator ma wyższy priorytet niż /operator. Jeśli chcesz logować się 5/0za pomocą podwójnego huku, musisz użyć !!(5/0).
matty

Odpowiedzi:


2743

Konwertuje Objectna boolean. Gdyby to było falsey (np 0, null, undefined, itd.), To będzie false, w przeciwnym razie true.

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

Więc !!to nie jest operator, to tylko !operator dwa razy.

Przykład ze świata rzeczywistego „Testuj wersję IE”:

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

Jeśli ⇒

console.log(navigator.userAgent.match(/MSIE 8.0/));  
// returns either an Array or null  

Ale jeśli ⇒

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

123
Konwertuje wartość inną niż boolean na odwróconą wartość logiczną (na przykład! 5 byłoby fałszem, ponieważ 5 jest wartością nie-fałszowaną w JS), a następnie odwraca wartość boolean, aby uzyskać oryginalną wartość jako wartość boolowską (więc !! 5 Mów prawdę).
Chuck,

111
Łatwy sposób to opisać: Boolean (5) === !! 5; Ten sam casting, mniej znaków.
Micah Snyder

39
Służy do konwertowania wartości true na wartość logiczną true, a wartości fałszowania na wartość boolean false.
thetoolman

13
@Micah Snyder należy uważać, aby w JavaScript lepiej było używać prymitywów boolowskich zamiast tworzyć obiekty, które zamykają booleany za pomocą nowej Boolean (). Oto przykład, aby zobaczyć różnicę: jsfiddle.net/eekbu
victorvartan

4
O ile mi wiadomo, ten wzorzec bang-bang nie jest użyteczny w instrukcji if (… _; tylko w instrukcji return funkcji, która powinna zwrócić wartość logiczną.
rds

853

To strasznie niejasny sposób na konwersję typu.

!NIE jest . Tak !truejest falsei !falsejest true. !0jest truei !1jest false.

Więc konwertujesz wartość na wartość logiczną, następnie odwracasz ją, a następnie ponownie odwracasz.

// Maximum Obscurity:
val.enabled = !!userId;

// Partial Obscurity:
val.enabled = (userId != 0) ? true : false;

// And finally, much easier to understand:
val.enabled = (userId != 0);

73
!! false = false. !! true = true
cllpse

89
Czy wariant „dużo łatwiejszy do zrozumienia” jest tutaj o wiele łatwiejszy do zrozumienia? Sprawdzanie z 0 nie jest faktycznym sprawdzaniem z 0, ale sprawdzanie z nieco dziwną listą wartości, które Javascript uważa za równe 0., userId ? true : false wyjaśnia, że ​​trwa konwersja i obsługuje przypadek, w którym wartość userId mogła zostać jawnie ustawiona naundefined
Ben Regenspan

54
Mój mózg nie ma problemu z dekodowaniem !!vardo Boolean(var)… i !!jest szybszy (mniej instrukcji do przetworzenia) i krótszy niż alternatywy.
adamJLev

7
@ RickyClarkson służy głównie do odczytu, ponieważ składniowo nie jest wymagany. Niektórzy stosują konwencję zawsze owijania warunek w nawiasie, aby odróżnić go od reszty wyrażenia.
Dave Rager

8
Nie zgadzam się z tym. userId != 0odnosi się do null, NaNi undefined, ale za fałszywe false. Jeśli chcesz dokładnie takie zachowanie, prawdopodobnie powinieneś wyrazić się jasno na ten temat. Ale nawet jeśli zadziałało dokładnie tak samo jak !!userId, nie jest jasne, czy chcesz , aby te wartości były fałszywe, czy też po prostu nie wziąłeś pod uwagę reguł konwersji typów JavaScript.
philh

449

!!exprzwraca wartość logiczną ( truelub false) w zależności od prawdziwości wyrażenia. Ma to większy sens, gdy jest używane w przypadku typów innych niż boolowskie. Rozważ te przykłady, zwłaszcza trzeci przykład i kolejne:

          !!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
Warto zauważyć:!!new Boolean(false) // true
Camilo Martin,

43
... ale także!!Boolean(false) // false
Camilo Martin,

97
new Boolean(false)jest przedmiotem, a obiekt jest prawdziwy, nawet jeśli zawiera wartość fałszu!
Salman A

3
Tak wiem, ale wziąć pod uwagę fakt, że większość rodzimych konstruktorów ( String, Number, Date, etc) mają być wpłacone jako funkcje zbyt, ale w tym przypadku wynik jest inny!
Camilo Martin,

4
@CamiloMartin: właśnie zdałem sobie sprawę, że new Boolean(false)zwraca objectchwilę, a Boolean(false)zwraca element podstawowy false . Mam nadzieję, że to ma sens.
Salman A

155

Zaparz herbatę:

!!nie jest operatorem. Jest to podwójne zastosowanie !- który jest logicznym operatorem „nie”.


W teorii:

! określa „prawdę” tego, czym nie jest wartość:

  • Prawda jest taka, że falsenie jest true(dlatego !falsewyniki w true)

  • Prawda jest taka, że truenie jest false(dlatego !truewyniki w false)


!!określa „prawdę” tego, czym nie jest wartość :

  • Prawdą jest, że truenie jest nie true (dlatego !!trueskutkuje true)

  • Prawdą jest, że falsenie jest nie false (dlatego !!falseskutkuje false)


To, co chcemy porównać w porównaniu, to „prawda” o wartości odwołania, a nie wartość samego odniesienia. Jest przypadek użycia, w którym możemy chcieć poznać prawdę o wartości, nawet jeśli oczekujemy, że wartość będzie false(lub falsey), lub jeśli spodziewamy się, że wartość nie będzie typu boolean.


W praktyce:

Rozważ zwięzłą funkcję, która wykrywa funkcjonalność funkcji (i w tym przypadku zgodność platformy) za pomocą dynamicznego pisania (inaczej „kaczego pisania”). Chcemy napisać funkcję, która zwraca, truejeśli przeglądarka użytkownika obsługuje <audio>element HTML5 , ale nie chcemy, aby funkcja generowała błąd, jeśli <audio>jest niezdefiniowany; i nie chcemy używać try ... catchdo obsługi ewentualnych błędów (ponieważ są obrzydliwe); a także nie chcemy używać kontroli wewnątrz funkcji, która nie będzie konsekwentnie ujawniać prawdy o tej funkcji (na przykład document.createElement('audio')nadal tworzy element wywoływany, <audio>nawet jeśli HTML5 <audio>nie jest obsługiwany).


Oto trzy podejścia:

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

Każda funkcja akceptuje argumenty dla <tag>i attributedo wyszukania, ale każda zwraca inne wartości w zależności od tego, co określają porównania.

Ale czekaj, jest więcej!

Niektórzy z was pewnie zauważyli, że w tym konkretnym przykładzie można po prostu sprawdzić właściwość, używając nieco bardziej wydajnych środków sprawdzania, czy przedmiotowy obiekt ma właściwość. Można to zrobić na dwa sposoby:

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

Dygresujemy ...

Jakkolwiek rzadko zdarzają się takie sytuacje, może istnieć kilka scenariuszy, w których trueużycie najbardziej zwięzłych, najbardziej wydajnych, a zatem najbardziej preferowanych sposobów uzyskiwania od wartości nie-logicznej, być może nieokreślonej !!. Mam nadzieję, że to absurdalnie to wyjaśnia.


1
całkowicie niesamowita odpowiedź, ale nie widzę użyteczności !! skonstruować. Ponieważ if()instrukcja już rzutuje wyrażenie na wartość logiczną, jawne rzutowanie wartości zwracanej funkcji testowej na wartość logiczną jest zbędne - ponieważ „prawdomówność” === jest prawdą w takim zakresie, w jakim if()oświadczenie się zgadza . A może brakuje mi scenariusza, w którym POTRZEBUJESZ prawdziwego wyrażenia, aby być naprawdę boolowskim true?
Tom Auger,

1
Instrukcje @TomAuger if()rzucają wartości logiczne na wartości falsey, ale mówią, że chcesz ustawić flagę boolowską na obiekcie - nie rzutuje to tak jak if()instrukcja. Na przykład object.hasTheThing = !!castTheReturnValToBoolNoMatterWhat()ustawi jedną truelub falsezamiast rzeczywistej wartości zwracanej. Innym przykładem może być to wszystkie administratorów są idz 0i nie-administratorów są id 1lub wyższej. Aby uzyskać, truejeśli ktoś nie jest administratorem, możesz to zrobić person.isNotAdmin = !!admin.id. Niewiele przypadków użycia, ale jest zwięzły, gdy jest.
Benny

103

!!konwertuje wartość po jej prawej stronie na równoważną wartość logiczną. (Pomyśl o sposobie „castingu” biednego człowieka). Jego celem jest zazwyczaj przekazanie czytelnikowi, że w kodzie nie ma znaczenia, jaką wartość ma zmienna, ale jaka jest jej wartość „prawda” .


4
Lub w przypadku wartości logicznej po prawej stronie nic nie robi.
Daniel A. White

3
@Daniel: !nadal odwraca wartość w prawo. W przypadku wartości logicznej skrajna prawa strona !neguje wartość, a !skrajna lewa ponownie ją neguje. Efektem netto jest to, że nie ma zmian, ale większość silników wygeneruje kody operacji dla podwójnej negacji.
Crescent Fresh

Ale o co chodzi? Jeśli tak, if(0){...JavaScript już wie, że to nieprawda. Dlaczego lepiej powiedzieć if(!!0){...?
CodyBugstein

chodzi o zmienne, które mogą nie znać jego zawartości; jeśli może być liczbą całkowitą lub łańcuchem, obiektem lub wartością zerową, niezdefiniowaną itp. Jest to łatwy sposób przetestowania istnienia.
mix3d

71

!!foostosuje dwukrotnie operator unary not i jest używany do rzutowania na typ logiczny podobny do użycia unary plus +foodo rzutowania na liczbę i łączenia pustego ciągu ''+foodo rzutowania na ciąg.

Zamiast tych hacków można również użyć funkcji konstruktora odpowiadających typom pierwotnym ( bez użycia new), aby jawnie rzutować wartości, tj.

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

Ale wtedy możesz napotkać problemy z instanceof. nowy Boolean (1) instanceof Object -> true !! 1 instanceof Object -> false
Seamus

13
nie, nie możesz: zauważ, że funkcje konstruktora są wywoływane bez new- jak wyraźnie wspomniano w mojej odpowiedzi
Christoph

2
fantastyczny! Jest to przydatne w przypadku małego włamania, gdy trzeba oszacować ciągi z „0” jako fałszem zamiast prawdy. (tzn. podczas odczytywania wartości z selekcji, ponieważ są one odczytywane jako Ciąg). Tak więc, jeśli chcesz uznać „0” za ujemne (boolean false), przy założeniu, że x="0"po prostu zrób: x=!!+x; //falseco jest tym samym, co Boolean(Number(x))liczba (lub + x) konwertuje ciąg „0” na 0, co ZALICZA wartość false, a następnie wartość boolowska (!! x) rzutuje to na wartość logiczną bezpośrednio. Bułka z masłem!
DiegoDD,

2
@DiegoDD dlaczego miałbyś wybrać !!+xvs x !== "0"?
placeybordeaux

@placeybordeaux, ponieważ na przykład możesz chcieć przekonwertować wartość i przypisać ją do innej zmiennej, niezależnie od tego, czy zamierzasz porównać ją z czymś innym, czy nie.
DiegoDD,

67

Tak wiele odpowiedzi robi połowę pracy. Tak, !!Xmożna to odczytać jako „prawdziwość X [przedstawionej jako logiczna]”. Ale !!praktycznie nie jest tak ważne, aby dowiedzieć się, czy pojedyncza zmienna jest (a nawet jeśli wiele zmiennych jest) prawdą czy fałszem. !!myVar === truejest taki sam jak sprawiedliwy myVar. Porównywanie !!Xdo „prawdziwych” wartości logicznych nie jest tak naprawdę przydatne.

Co można zyskać ze !!jest możliwość sprawdzenia truthiness wielu zmiennych przeciwko siebie w powtarzalny, standaryzowane (a) JSLint przyjazny sposób.

Po prostu casting :(

To jest...

  • 0 === falsejest false.
  • !!0 === falsejest true.

Powyższe nie jest tak przydatne. if (!0)daje takie same wyniki jak if (!!0 === false). Nie mogę wymyślić dobrego argumentu za rzutowaniem zmiennej na wartość logiczną, a następnie na porównanie z „prawdziwą” wartością logiczną.

Zobacz „== i! =” Ze wskazówek JSLinta (uwaga: Crockford trochę przesuwa swoją stronę; ten link może umrzeć w pewnym momencie), aby dowiedzieć się, dlaczego:

Operatory == i! = Dokonują przymusu typu przed porównaniem. Jest to złe, ponieważ powoduje, że '\ t \ r \ n' == 0 jest prawdą. Może to maskować błędy typu. JSLint nie może wiarygodnie ustalić, czy == jest używane poprawnie, dlatego najlepiej nie używać w ogóle == i! = I zawsze używać bardziej niezawodnych operatorów === i! ==.

Jeśli zależy ci tylko na tym, że wartość jest prawdą lub fałszem, skorzystaj z krótkiej formy. Zamiast
(foo != 0)

tylko powiedz
(foo)

i zamiast
(foo == 0)

mówić
(!foo)

Należy zauważyć, że istnieją nieintuicyjne przypadki, w których wartość logiczna zostanie rzutowana na liczbę ( truejest rzutowana na 1i falsena 0) podczas porównywania wartości logicznej z liczbą. W takim przypadku !!może być przydatny psychicznie. Chociaż znowu są to przypadki, w których porównujesz nie-boolean z booleanem o twardym typie, co jest, imo, poważnym błędem. if (-1)jest wciąż do zrobienia tutaj.

╔═══════════════════════════════════════╦═══════════════════╦═══════════╗
               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
╚═══════════════════════════════════════╩═══════════════════╩═══════════╝

A wszystko staje się jeszcze bardziej szalone w zależności od silnika. Na przykład WScript wygrywa nagrodę.

function test()
{
    return (1 === 1);
}
WScript.echo(test());

Z powodu jakiegoś historycznego jive Windowsa , to wyświetli -1 w oknie komunikatu! Wypróbuj w wierszu polecenia cmd.exe i przekonaj się! Ale WScript.echo(-1 == test())wciąż daje ci 0 lub WScript false. Odwracać wzrok. To ohydne.

Porównywanie prawdy :)

Ale co, jeśli mam dwie wartości, muszę sprawdzić równość truthi / falsi-nizm?

Udawaj, że mamy myVar1 = 0;i myVar2 = undefined;.

  • myVar1 === myVar2jest 0 === undefinedi jest oczywiście fałszywe.
  • !!myVar1 === !!myVar2jest !!0 === !!undefinedi jest prawdą! Ta sama prawda! (W tym przypadku oba „mają prawdziwość fałszu”).

Tak więc jedynym miejscem, w którym naprawdę potrzebowałbyś użyć „zmiennych obsadzonych logicznie” byłoby, gdybyś miał sytuację, w której sprawdzasz, czy obie zmienne mają tę samą prawdziwość, prawda? To znaczy, użyj, !!jeśli chcesz zobaczyć, czy dwie zmienneprawdomówne, czy obie fałszywe (lub nie), to znaczy o równej (lub nie) prawdomówności .

Nie mogę wymyślić świetnego, nieskomplikowanego przypadku użycia dla tego odręcznego. Może masz „połączone” pola w formularzu?

if (!!customerInput.spouseName !== !!customerInput.spouseAge ) {
    errorObjects.spouse = "Please either enter a valid name AND age " 
        + "for your spouse or leave all spouse fields blank.";
}

Więc teraz, jeśli masz prawdę dla obu lub fałsz zarówno dla nazwiska małżonka, jak i wieku, możesz kontynuować. W przeciwnym razie masz tylko jedno pole z wartością (lub bardzo wczesne małżeństwo) i musisz stworzyć dodatkowy błąd w swojej errorObjectskolekcji.


EDYCJA 24 października 2017 r., 6 lutego 19:

Biblioteki stron trzecich, które oczekują wyraźnych wartości logicznych

Oto interesujący przypadek ... !!może być przydatny, gdy biblioteki innych firm oczekują wyraźnych wartości logicznych.

Na przykład Fałsz w JSX (React) ma specjalne znaczenie, które nie jest wywoływane w przypadku zwykłego fałszu. Jeśli próbowałeś zwrócić coś takiego w JSX, oczekując int w messageCount...

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

... możesz być zaskoczony, gdy React renderuje, 0gdy masz zero wiadomości. Musisz jawnie zwrócić wartość false, aby JSX nie renderował. Powyższa instrukcja zwraca 0, którą JSX chętnie renderuje, tak jak powinien. Nie może powiedzieć, że nie miałeś Count: {messageCount && <div>Get your count to zero!</div>}(lub czegoś mniej wymyślonego).

  • Jedna poprawka wymaga bangbang, przekształcająca 0się !!0, co jest false:
    {!!messageCount && <div>You have messages!</div>}

  • Dokumenty JSX sugerują, abyś był bardziej jednoznaczny, napisał kod do komentowania i użył porównania, aby wymusić wartość logiczną.
    {messageCount > 0 && <div>You have messages!</div>}

  • Bardziej komfortowo radzę sobie z fałszowaniem za pomocą trójki -
    {messageCount ? <div>You have messages!</div> : false}

Ta sama sprawa w Typescript: Jeśli masz funkcję, która zwraca wartość logiczną (lub przypisujesz wartość zmiennej boolean), zwykle nie możesz zwrócić / przypisać wartości boolean-y; musi to być silnie typ logiczny. Oznacza to, że iff myObjectjest silnie wpisany , return !myObject;działa dla funkcji zwracającej wartość logiczną, ale return myObject;nie działa. Musisz return !!myObjectdopasować się do oczekiwań maszynopisu.

Wyjątek dla maszynopisu? Jeśli myObjecttak any, to wracasz do Dzikiego Zachodu JavaScript i możesz go zwrócić bez niego !!, nawet jeśli typ zwrotu to wartość logiczna.

Pamiętaj, że to konwencje JSX i maszynopisu , a nie te związane z JavaScript .

Ale jeśli widzisz dziwne 0znaki w renderowanym JSX, pomyśl luźne zarządzanie fałszem.


Dobre wytłumaczenie. Więc powiedziałbyś !! nie jest absolutnie konieczne w tym przykładzie wykrywania funkcji pracownika ? if (!!window.Worker)
jk7

2
Nie, nie potrzebujesz tego. Prawdomówność i true„zewnętrznie” działają dokładnie tak samo if. Wciąż próbuję, ale nie mogę wymyślić powodu, dla którego wolałbym przekazywać prawdomówność na wartość boolowską poza takim złożonym przypadkiem „porównaj prawdy” powyżej, z wyjątkiem czytelności, jeśli użyjesz tej wartości później, jak w qprzykładzie z biblioteki . Ale nawet wtedy jest to skrót do utraty informacji i twierdzę, że lepiej za każdym razem oceniać prawdziwość.
ruffin

Reakcja jest głównym powodem, dla którego zaczęliśmy używać !! wzór, ale zdarza się, że jest to bardzo wygodna i powtarzalna rzecz. Muszę się tylko martwić o prawdziwość lub fałszywość czegoś, a nie o to, jaki jest jego typ.

Komentarze negatywne bez komentarzy utrudniają rozwiązanie problemu! Daj mi znać, co wygląda źle, a chętnie się tym zajmę.
ruffin

55

To tylko logiczny operator NOT, dwa razy - służy do konwersji czegoś na wartość logiczną, np .:

true === !!10

false === !!0

3
Dlaczego, u licha, miałbyś to robić? Użyj ! operator przekonwertować na wartość logiczną, a następnie użyć ===, aby porównać typ? Po prostu zaakceptuj brak bezpieczeństwa typu i zrób val> 0 lub coś takiego.
Darren Clark

43
@Darren: Nie porównuje typów; mówi wam, jakie są wyniki, pisząc twierdzenia w swojej odpowiedzi.
Wyścigi lekkości na orbicie


26

To podwójna notoperacja. Pierwszy !konwertuje wartość na wartość logiczną i odwraca jej wartość logiczną. Drugi !odwraca wartość logiczną z powrotem.


26

Wydaje się, że !!operator skutkuje podwójną negacją.

var foo = "Hello World!";

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

23

Symuluje zachowanie Boolean()funkcji rzutowania. Pierwszy NOTzwraca wartość logiczną bez względu na podany operand. Drugi NOTneguje tę Booleanwartość i dlatego podaje truewartość logiczną zmiennej. Wynik końcowy jest taki sam, jak użycie Boolean()funkcji dla wartości.


20

! to „boolean not”, który zasadniczo rzutuje wartość „enable” na swoją logiczną wartość przeciwną. Drugi ! odwraca tę wartość. Tak, !!enableoznacza „nie należy włączać”, co daje wartość enablejako wartość logiczną.


18

Myślę, że warto wspomnieć, że warunek połączony z logicznym AND / OR nie zwróci wartości logicznej, ale ostatni sukces lub pierwszy błąd w przypadku && i pierwszy sukces lub ostatni błąd w przypadku || łańcucha warunków.

res = (1 && 2); // res is 2
res = (true && alert) // res is function alert()
res = ('foo' || alert) // res is 'foo'

Aby przerzucić warunek na prawdziwy logiczny literał, możemy użyć podwójnej negacji:

res = !!(1 && 2); // res is true
res = !!(true && alert) // res is true
res = !!('foo' || alert) // res is true

17

!!używa NOToperacji dwa razy razem, !przekonwertuj wartość na a booleani odwróć ją, oto prosty przykład, aby zobaczyć, jak !!działa:

Na początku masz miejsce:

var zero = 0;

Następnie zrobisz to !0, zostanie przekonwertowane na wartość logiczną i zostanie ocenione na true, ponieważ 0 jest falsy, więc otrzymasz odwróconą wartość i przekonwertowane na wartość logiczną, więc zostanie to ocenione na true.

!zero; //true

ale nie chcemy odwróconej boolowskiej wersji wartości, więc możemy ją odwrócić, aby uzyskać nasz wynik! Dlatego używamy innego !.

Zasadniczo, !!upewnij się, że otrzymujemy wartość boolowską, a nie fałsz, prawdę, łańcuch itp.

To tak, jakby używać Booleanfunkcji w javascript, ale w łatwy i krótszy sposób przekonwertować wartość na wartość logiczną:

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

15

!!Konstrukt jest prostym sposobem toczenia dowolne wyrażenie JavaScript do jej logicznego odpowiednika.

Na przykład: !!"he shot me down" === truei !!0 === false.


2
Bardzo blisko ważnego rozróżnienia. Kluczem jest to, że 0 === falsejest fałszywe i !!0 === falseprawdziwe.
ruffin

14

To nie jest pojedynczy operator, to dwa. Jest to równoważne z poniższym i jest szybkim sposobem na rzutowanie wartości na wartość logiczną.

val.enabled = !(!enable);

10

Podejrzewam, że jest to pozostałość po C ++, gdzie ludzie nadpisują! operator, ale nie operator bool.

Aby uzyskać odpowiedź negatywną (lub pozytywną) w takim przypadku, najpierw musisz użyć! operator, aby uzyskać wartość logiczną, ale jeśli chcesz sprawdzić, pozytywny przypadek użyłby !!.


10

ifI whileoświadczenia oraz ?wartości stosowanie prawdy operatora w celu określenia, która gałąź uruchomienie kodu. Na przykład liczby zero i NaN oraz pusty ciąg są fałszywe, ale inne liczby i ciągi są prawdziwe. Obiekty są prawdziwe, ale nieokreślona wartość i nulloba są fałszywe.

Operator podwójnej negacji !!oblicza wartość prawdy wartości. W rzeczywistości są to dwa operatory, które !!xoznaczają !(!x)i zachowują się następująco:

  • Jeśli xjest wartością fałszywą, !xjest truei !!xjest false.
  • Jeśli xjest prawdziwą wartością, !xjest falsei !!xjest true.

W przypadku zastosowania na górnym poziomie logicznej związku ( if, while, i ?), przy czym !!podmiot jest behawioralnie nie-OP. Na przykład if (x)i if (!!x)znaczy to samo.

Praktyczne zastosowania

Ma jednak kilka praktycznych zastosowań.

Jednym z zastosowań jest stratna kompresja obiektu do jego wartości prawdziwej, aby Twój kod nie zawierał odniesienia do dużego obiektu i nie utrzymywał go przy życiu. Przypisanie !!some_big_objectzmiennej zamiast some_big_objectpuszczania jej dla śmieciarza. Jest to przydatne w przypadkach, które generują obiekt lub wartość fałszywą, taką jak nullwartość niezdefiniowana, na przykład wykrywanie funkcji przeglądarki.

Innym zastosowaniem, o którym wspomniałem w odpowiedzi na temat odpowiedniego !!operatora C , są narzędzia „kłaczków”, które szukają typowych literówek i diagnostyki drukowania. Na przykład, zarówno w języku C, jak i JavaScript, kilka typowych literówek dla operacji boolowskich wywołuje inne zachowania, których wynik nie jest taki sam jak wartość logiczna:

  • if (a = b)jest przypisaniem, po którym następuje użycie wartości prawdy b; if (a == b)to porównanie równości.
  • if (a & b)jest nieco bitowe AND; if (a && b)jest logicznym AND. 2 & 5jest 0(wartość fałszywa); 2 && 5jest prawdziwy.

!!Operator uspokaja narzędzie niestrzępiącą, że to co napisałeś jest to, co masz na myśli: czy ta operacja, a następnie podjąć wartość logiczną wyniku.

Trzecim zastosowaniem jest stworzenie logicznego XOR i logicznego XNOR. Zarówno w języku C, jak i JavaScript a && bwykonuje logiczne AND (prawda, jeśli obie strony są prawdziwe) i a & bwykonuje bitowe AND. a || bwykonuje logiczną a | boperację OR (prawda, jeśli przynajmniej jedna jest prawdą) i wykonuje bitową operację LUB. Istnieje bitowy XOR (wyłączny OR) a ^ b, ale nie ma wbudowanego operatora dla logicznego XOR (prawda, jeśli prawda jest dokładnie jedna strona). Możesz na przykład pozwolić użytkownikowi na wprowadzenie tekstu w dokładnie jednym z dwóch pól. Co można zrobić, to przekonwertować każdy o wartości logicznej i porównać je: !!x !== !!y.



8

Mnóstwo świetnych odpowiedzi tutaj, ale jeśli przeczytałeś tak daleko, pomogło mi to „zdobyć”. Otwórz konsolę w Chrome (itp.) I zacznij pisać:

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

Oczywiście wszystkie są takie same jak zwykłe pisanie !! coś, ale dodane nawiasy mogą pomóc w zrozumieniu.


8

!!x jest skrótem od Boolean(x)

Pierwszy huk zmusza silnik js do uruchomienia, Boolean(x)ale ma również efekt uboczny polegający na odwróceniu wartości. Drugi huk usuwa efekt uboczny.


8

Zmusza wszystkie rzeczy do boolean.

Na przykład:

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

Odpowiedź na to pytanie jest dość dokładna, ale chciałbym dodać odpowiedź, która, mam nadzieję, jest tak uproszczona, jak to możliwe, dzięki czemu !! tak proste, jak to tylko możliwe.

Ponieważ javascript ma tak zwane wartości „prawdomówne” i „falsey”, istnieją wyrażenia, które po ocenie w innych wyrażeniach spowodują powstanie warunku prawdziwego lub fałszywego, nawet jeśli badana wartość lub wyrażenie nie jest w rzeczywistości truelub false.

Na przykład:

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

Jeśli ten element faktycznie istnieje, wyrażenie zostanie ocenione jako prawda, a blok kodu zostanie wykonany.

Jednak:

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

... NIE spowoduje prawdziwego warunku, a blok kodu nie zostanie wykonany, nawet jeśli element istnieje.

Dlaczego? Ponieważ document.getElementById()jest to „prawdomówne” wyrażenie, które w tym if()stwierdzeniu zostanie ocenione jako prawdziwe , ale nie jest rzeczywistą wartością logiczną true.

Podwójne „nie” w tym przypadku jest dość proste. To po prostu dwie notsekundy do siebie.

Pierwszy z nich po prostu „odwraca” wartość prawdy lub falseya, co skutkuje rzeczywistym typem logicznym, a następnie drugi „odwraca” go z powrotem do pierwotnego stanu, ale teraz w rzeczywistą wartość logiczną. W ten sposób masz spójność:

if (!!document.getElementById('myElement')) {}

i

if (!!document.getElementById('myElement') == true) {}

ZARÓWNO zwróci true, zgodnie z oczekiwaniami.


7

Chciałem tylko to dodać

if(variableThing){
  // do something
}

jest taki sam jak

if(!!variableThing){
  // do something
}

Ale może to być problem, gdy coś jest niezdefiniowane.

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

Sztuczka polega na tym, że łańcuch &&s zwróci pierwszą znalezioną wartość falsey - i można ją podać do instrukcji if itp. Więc jeśli b.foo jest niezdefiniowany, zwróci niezdefiniowaną i pominie b.foo.barinstrukcję, a my nie otrzymamy błąd.

Powyższy zwrot niezdefiniowana, ale jeśli masz pusty ciąg, fałszywe, null, 0 niezdefiniowane wartości te powrócą i zaraz spotykamy je w sieci - []i {}to zarówno „truthy” i będziemy kontynuować w dół tak zwany " && chain ”do następnej wartości po prawej stronie.

PS Innym sposobem na zrobienie tego samego jest to (b || {}).foo, że jeśli b jest niezdefiniowane, to b || {}będzie {}, a będziesz uzyskiwał dostęp do wartości w pustym obiekcie (bez błędu) zamiast próbować uzyskać dostęp do wartości w „niezdefiniowanym” (powoduje błąd ). Więc (b || {}).foojest taki sam jak b && b.fooi ((b || {}).foo || {}).barjest taki sam jak b && b.foo && b.foo.bar.


dobra uwaga - zmieniłem moją odpowiedź. Zdarza się to tylko na obiekcie, gdy jest zagnieżdżony na trzech poziomach głębokości, ponieważ, jak powiedziałeś ({}).anything, daundefined
Ryan Taylor

5

Po zobaczeniu wszystkich tych wspaniałych odpowiedzi chciałbym dodać kolejny powód do korzystania !!. Obecnie pracuję w Angular 2-4 (TypeScript) i chcę zwrócić wartość logiczną, falsegdy mój użytkownik nie jest uwierzytelniony. Jeśli nie jest uwierzytelniony, ciągiem tokenów będzie nulllub "". Mogę to zrobić, używając następnego bloku kodu:

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

4

oto fragment kodu z kątowego js

var requestAnimationFrame = $window.requestAnimationFrame ||
                                $window.webkitRequestAnimationFrame ||
                                $window.mozRequestAnimationFrame;

 var rafSupported = !!requestAnimationFrame;

ich zamiarem jest ustawienie rafSupported na true lub false na podstawie dostępności funkcji w requestAnimationFrame

można to osiągnąć, ogólnie sprawdzając w następujący sposób:

if(typeof  requestAnimationFrame === 'function')
rafSupported =true;
else
rafSupported =false;

krótką drogą może być użycie !!

rafSupported = !!requestAnimationFrame ;

więc jeśli funkcja requestAnimationFrame ma przypisaną funkcję, to parametr requestAnimationFrame będzie fałszywy i jeszcze jeden! byłoby to prawdą

jeśli requestAnimationFrame został przyjęty jako niezdefiniowany, to! requestAnimationFrame byłoby prawdziwe i jeszcze jedno! byłoby to fałszywe


3

Niektóre operatory w JavaScript wykonują niejawne konwersje typów, a czasem są używane do konwersji typów.

Jednoargumentowy !operator przekształca swój operand na wartość logiczną i neguje go.

Ten fakt prowadzi do następującego idiomu, który można zobaczyć w kodzie źródłowym:

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

3

Użyj logicznego operatora nie dwa razy,
co oznacza! Prawda = fałsz
i !! prawda = prawda


3

Zwraca wartość logiczną zmiennej.

Zamiast tego Booleanmożna użyć klasy.

(proszę przeczytać opisy kodów)

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`

Mianowicie Boolean(X) = !!Xw użyciu.

Sprawdź fragment kodu poniżej

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.