javascript - Konverter boolean-resultat til tall/hele tall


Jeg har en variabel som lagrer false eller true, men jeg trenger 0 eller 1 i stedet, henholdsvis. Hvordan kan jeg gjøre dette?

Svar #1

Bruk den unære +-operatoren, som konverterer operanden sin til et tall.

+ true; // 1
+ false; // 0

Merk, selvfølgelig, at du fortsatt bør rense dataene på serversiden, fordi en bruker kan sende hvilken som helst data til serveren din, uansett hva klientkode sier.

Svar #2

Javascript har en ternæroperator du kan bruke:

var i = result ? 1 : 0;

Svar #3

Etter min mening er den beste løsningen:

fooBar | 0

Dette brukes i asm.js for å tvinge heltallstype.

Svar #4

Jeg foretrekker å bruke Number-funksjonen. Den tar et objekt og konverterer det til et tall.

Eksempel :

var myFalseBool = false;
var myTrueBool = true;

var myFalseInt = Number(myFalseBool);
console.log(myFalseInt === 0);

var myTrueInt = Number(myTrueBool);
console.log(myTrueInt === 1);

Du kan teste det i en jsFiddle.

Svar #5

Den typede måten å gjøre dette på ville være:

Number(true) // 1
Number(false) // 0

Svar #6

Jeg laget en JSperf-sammenligning av alle foreslåtte svar.

TL;DR - det beste alternativet for alle nåværende nettlesere er:

val | 0;

.

Oppdatering:

Det virker som om de i disse dager alle er ganske identiske, bortsett fra at Number()-funksjonen er den tregeste, mens den beste er val === true ? 1 : 0;.

Svar #7

Jeg kom over denne snarveien i dag.

~~(sann)

~~(usann)

Folk som er mye smartere enn meg kan forklare:

http://james.padolsey.com/javascript/double-bitwise-not/

Svar #8

TL;DR: Unngå Number-konstruktøren og +bool; bruk en enkel if som standard; ty til bool | 0, 1 * bool hvis benchmarks i prosjektet ditt fungerer bedre på denne måten.

Dette er et ganske gammelt spørsmål, og det finnes mange gyldige svar. Noe jeg har lagt merke til er at alle benchmarkene her er irrelevante - ingen tar hensyn til grenforutsigelse. I dag gjør heller ikke JS-motorer bare å tolke koden, de JIT-kompilerer den til native maskinkode og optimaliserer den før kjøring. Dette betyr at, i tillegg til grenforutsigelse, kan kompilatoren til og med erstatte uttrykk med deres endelige verdi.

Nå, hvordan påvirker disse to faktorene ytelsen til, vel, konvertering fra boolean til heltall? La oss finne det ut! Før vi går inn i testene, er det viktig å vite hva vi tester. For konverteringen bruker vi følgende syv konverteringsmetoder:

  • Number-konstruktør: Number(bool)
  • If-setning (ternær brukt): bool ? 1 : 0
  • Unær operator +: +bool
  • Bitvis ELLER: bool | 0
  • Bitvis OG: bool & 1
  • Bitvis dobbel IKKE: ~~bool
  • Talls multiplikasjon: bool * 1

"Konvertering" betyr å konvertere false til 0 og true til 11. Hver konverteringsmetode kjøres 100000 ganger, og operasjoner/millisecond måles. I de følgende tabellene vil konverteringsmetoder grupperes etter deres resultater. Prosentandelen etter resultatet viser hvor mye tregere denne metoden er sammenlignet med den raskeste i samme nettleser. Hvis det ikke er noen prosentandel, er metoden enten den raskeste eller forskjellen er ubetydelig (<0,01%). Benchmark-testene kjøres på en Macbook Pro 16-tommers maskin, med Apple M1 Pro 10-kjerners CPU og 16 GB RAM. Nettlesere er Chrome 102, Firefox 101 og Safari 15.5.

Det første referansepunktet konverterer konstanten true:

MetodeChrome (V8)Firefox (Spidermonkey)Safari (Webkit)
Number(bool)31745.89392.35 - 91.48%31231.79
bool ? 1 : 031592.8 - 0.48%4602.6427533.47 - 11.84%
+bool31332.57 - 1.3%4463.41 - 3.02%27378.7 - 12.34%
bool | 031488.5 - 0.81%4441.4 - 3.5%27222 - 12.84%
bool & 131383.17 - 1.14%4459.64 - 3.11%27317.41 - 12.53%
~~bool31265.85 - 1.51%4442.35 - 3.48%27434.72 - 12.16%
bool * 131374.4 - 1.17%4444.05 - 3.45%27381.19 - 12.33%

Interessant! V8 viser noen enorme tall, alle omtrent like! Spidermonkey skinner egentlig ikke, men vi kan se at bitvise og multiplikasjonstriksene kommer først, og den ternære if-en kommer som nummer to. Til slutt gjør Webkits Number noe lignende V8s, og de andre metodene kommer bak, men ligger alle tett sammen. Hva kan vi ta med oss? Nettlesere klarer stort sett å erstatte konverteringene våre med ganske enkelt verdien 1. Denne optimaliseringen vil skje der vi mentalt kan erstatte boolean med en konstant verdi. Number-konstruktøren er en interessant anomali - den faller kraftig bak i Firefox (91% langsommere!), mens den i Safari er den raskeste!

Det ovenfor er ikke en situasjon vi noen gang vil støte på i virkelige prosjekter. Så la oss endre variablene våre: boolen er nå Math.random() < 0.5. Dette gir 50 % sjanse for true, 50 % for false. Endrer resultatene våre seg? La oss kjøre denne benchmarken for å se.

MetodeChrome (V8)Firefox (Spidermonkey)Safari (Webkit)
Number(bool)1648.83 - 2.26%280.34 - 86.4%8014.69
bool ? 1 : 0804.27 - 52.32%731.57 - 64.5%1294.02 - 83.85%
+bool1670.79 - 0.95%2057.947753.99 - 3.25%
bool | 01668.22 - 1.11%2054.177764.81 - 3.12%
bool & 11675.52 - 0.67%2056.767193.08 - 10.25%
~~bool1676.24 - 0.63%2056.187669.48 - 4.31%
bool * 11686.882060.887751.48 - 3.28%

Resultatene er mer konsistente nå. Vi ser lignende tall for ternær if, bitvise operasjoner og multiplikasjonsmetoder på tvers av nettlesere, og Number-konstruktøren presterer igjen dårligst på Firefox. Ternær kommer bak, da den genererer grener. Safari ser ut til å være vår beste ytelsesmessig totalt sett, med hver metode som gir lynraske resultater!

La oss nå se hvordan grenforutsigelse påvirker resultatene våre med følgende benchmark, hvor vi endrer vår boolske variabel til Math.random() < 0.01, som betyr 1% true, 99% false.

MetodeChrome (V8)Firefox (Spidermonkey)Safari (Webkit)
Number(bool)1643.13 - 1.68%280.06 - 86.4%8071.65
bool ? 1 : 01590.55 - 4.83%1970.66 - 4.32%7119.59 - 11.8%
+bool1662.09 - 0.55%2054.097762.03 - 3.84%
bool | 01669.352051.857743.95 - 4.06%
bool & 11661.09 - 0.61%2057.627454.45 - 7.65%
~~bool1662.94 - 0.5%2059.657739.4 - 4.12%
bool * 11671.282048.217787.38 - 3.52%

Uventet? Forventet? Jeg vil si det siste, fordi i dette tilfellet var grenforutsigelsen vellykket i nesten alle tilfeller, gitt den lille forskjellen mellom ternær if og bitvise hacks. Alle andre resultater er de samme, ikke mye annet å si her. Jeg vil fortsatt påpeke den fryktelige ytelsen til Number i Firefox - hvorfor?

Denne innsatsen bringer oss tilbake til det opprinnelige spørsmålet: hvordan konvertere bool til int i Javascript? Her er mine forslag:

  • Bruk if-setninger, generelt. Ikke prøv å være smart - nettleseren gjør det vanligvis bedre, og vanligvis betyr de fleste situasjoner. De er de mest lesbare og tydelige av alle metodene her. Mens vi er inne på lesbarhet, bruk kanskje if (bool) i stedet for den stygge ternary-operatøren! Jeg skulle ønske Javascript hadde det Rust eller Python har...
  • Bruk resten når det virkelig er nødvendig. Kanskje ytelsestestene i prosjektet ditt presterer under standard, og du har funnet ut at en skikkelig if forårsaker dårlig ytelse - hvis det er tilfelle, føl deg fri til å gå inn i branchless-programmering! Men ikke gå for dypt ned i det kaninhullet, ingen vil ha nytte av ting som -1 * (a < b) + 1 * (a > b), tro meg.

Og noen spesifikasjoner:

  • Unngå Number(bool). Selv om det er sant at Chromium-plattformen (Chrome + Edge) har omtrent 68 % markedsandel globalt, Safari 19 % og Firefox kun 3,6 %, finnes det nok andre raske metoder som ikke vil ofre en prosentandel av brukerne dine helt. Firefox har 7 % markedsandel på desktop, noe som utgjør et betydelig antall på 173 millioner brukere.
  • I eldre referansetester presterte +bool like dårlig som Number i Firefox, kanskje ta dette i betraktning også - bitvise triks og multiplikasjon gir konsekvent gode resultater i alle nettlesere, i alle situasjoner. bool | 0 har størst sjanse for å være kjent for andre utviklere.

REDIGER: Det forrige benchmarking-verktøyet ga vage resultater, uten en måleenhet. Jeg har endret det, og har også lagt til benchmarking for Safari, som har påvirket konklusjonene.


  1. Definerte konverteringen fordi det ikke er helt klart hva boolean til heltall betyr. For eksempel støtter ikke Go denne konverteringen i det hele tatt.

Svar #9

Når JavaScript forventer en tallverdi, men mottar en boolsk verdi i stedet, konverterer det den boolske verdien til et tall: true og false konverteres henholdsvis til 1 og 0. Så du kan dra nytte av dette;

var t = true;
var f = false;

console.log(t*1); // t*1 === 1
console.log(f*1); // f*1 === 0 

console.log(+t); // 0+t === 1 or shortened to +t === 1
console.log(+f); //0+f === 0 or shortened to +f === 0

Videre lesning Typekonverteringer Kapittel 3.8 i Den definitive guiden til Javascript.

Svar #10

Jeg holdt nettopp på med dette problemet i noe kode jeg skrev. Min løsning var å bruke en bitvis og.

var j = bool & 1;

En raskere måte å håndtere et konstant problem på ville være å lage en funksjon. Det er mer lesbart for andre, bedre for forståelse på vedlikeholdsstadiet, og fjerner potensialet for å skrive noe feil.

function toInt( val ) {
    return val & 1;
}

var j = toInt(bool);

Rediger - 10. september 2014

Ingen konvertering ved bruk av en ternæroperator med likhetsoperatoren er raskere i Chrome av en eller annen grunn. Det gir ingen mening hvorfor det er raskere, men jeg antar det er en form for lavnivåoptimalisering som gir mening et sted underveis.

var j = boolValue === true ? 1 : 0;

Test det selv: http://jsperf.com/boolean-int-conversion/2

I FireFox og Internet Explorer er det generelt raskere å bruke versjonen jeg la ut.

Rediger - 14. juli 2017

Ok, jeg kommer ikke til å fortelle deg hvilken du bør eller ikke bør bruke. Hver eneste jævla nettleser har gått opp og ned i hvor raskt de kan utføre operasjonen med hver metode. Chrome hadde på et tidspunkt faktisk den bitvise &-versjonen som gjorde det bedre enn de andre, men så ble den plutselig mye verre. Jeg vet ikke hva de driver med, så jeg lar det bare være med hvem som bryr seg. Det er sjelden noen grunn til å bry seg om hvor raskt en operasjon som dette utføres. Selv på mobil er det en ubetydelig operasjon.

Også, her er en nyere metode for å legge til en 'toInt'-prototype som ikke kan overskrives.

Object.defineProperty(Boolean.prototype, "toInt", { value: function()
{
    return this & 1;
}});

Svar #11

Den unære +-operatoren vil ta seg av dette:

var test = true;
// +test === 1
test = false;
// +test === 0

Du vil naturligvis ønske å sjekke dette på serveren før du lagrer det, så det kan uansett være et mer fornuftig sted å gjøre dette.

Svar #12

Du kan også legge til 0, bruke skiftoperatorer eller xor:

val + 0;
val ^ 0;
val >> 0;
val >>> 0;
val << 0;

Disse har lignende hastigheter som de fra de andre svarene.

Svar #13

I min kontekst, React Native hvor jeg får opasitetsverdien fra en boolsk verdi, den enkleste måten: Bruk den unære + -operatoren.

+ true; // 1
+ false; // 0

Dette konverterer booleanen til et tall;

style={ opacity: +!isFirstStep() }

Relaterte artikler