parseInt vs unary plus, wann welche verwenden?

149

Was sind die Unterschiede zwischen dieser Zeile:

var a = parseInt("1", 10); // a === 1

und diese Zeile

var a = +"1"; // a === 1

Dieser jsperf-Test zeigt, dass der unäre Operator in der aktuellen Chrome-Version viel schneller ist, vorausgesetzt, es handelt sich um node.js!?

Wenn ich versuche, Zeichenfolgen zu konvertieren, die keine Zahlen sind, geben beide Folgendes zurück NaN:

var b = parseInt("test" 10); // b === NaN
var b = +"test"; // b === NaN

Also, wann sollte ich es vorziehen, parseIntdas unäre Plus zu verwenden (besonders in node.js) ???

edit : und was ist der Unterschied zum Double Tilde Operator ~~?

hereandnow78
quelle
1
Benchmark jsperf.com/parseint-vs-unary-operator
Roko C. Buljan

Antworten:

169

In dieser Antwort finden Sie eine vollständigere Sammlung von Fällen




Nun, hier sind einige Unterschiede, die ich kenne:

  • Eine leere Zeichenfolge wird zu a ""ausgewertet 0, während parseIntsie zu a ausgewertet wird NaN. IMO sollte eine leere Zeichenfolge a sein NaN.

    +'' === 0;              //true
    isNaN(parseInt('',10)); //true
  • Das Unäre +verhält sich eher so, parseFloatals würde es auch Dezimalstellen akzeptieren.

    parseIntAuf der anderen Seite wird das Parsen beendet, wenn ein nicht numerisches Zeichen angezeigt wird, z. B. der Punkt, der als Dezimalpunkt gedacht ist ..

    +'2.3' === 2.3;           //true
    parseInt('2.3',10) === 2; //true
  • parseIntund parseFloatanalysiert und erstellt die Zeichenfolge von links nach rechts . Wenn sie ein ungültiges Zeichen sehen, wird zurückgegeben, was (falls vorhanden) als Zahl NaNanalysiert wurde , und wenn keines als Zahl analysiert wurde.

    Das Unary +hingegen wird zurückgegeben, NaNwenn die gesamte Zeichenfolge nicht in eine Zahl konvertierbar ist.

    parseInt('2a',10) === 2; //true
    parseFloat('2a') === 2;  //true
    isNan(+'2a');            //true
  • Wie im Kommentar von gesehen @ Alex K. , parseIntund parseFloatwird durch Zeichen analysieren. Dies bedeutet, dass Hex- und Exponentennotationen fehlschlagen, da die xund eals nicht numerische Komponenten behandelt werden (zumindest auf base10).

    Der Unary +wird sie jedoch richtig konvertieren.

    parseInt('2e3',10) === 2;  //true. This is supposed to be 2000
    +'2e3' === 2000;           //true. This one's correct.
    
    parseInt("0xf", 10) === 0; //true. This is supposed to be 15
    +'0xf' === 15;             //true. This one's correct.
Joseph
quelle
6
Auch bei Verwendung eines Radix+"0xf" != parseInt("0xf", 10)
Alex K.
Ihre Antwort gefällt mir bisher am besten. Können Sie auch erklären, was der Unterschied zum Doppel-Tilde-Operator ~~ ist?
hereandnow78
@ hereandnow78 Das würde hier erklärt . Es ist bitweise äquivalent zu Math.floor(), was im Grunde den Dezimalteil abschneidet.
Joseph
4
Eigentlich "2e3"ist keine gültige Ganzzahldarstellung für 2000. Es ist jedoch eine gültige Gleitkommazahl: parseFloat("2e3")Wird 2000als Antwort korrekt ausgegeben. Und "0xf"erfordert mindestens Basis 16, weshalb parseInt("0xf", 10)zurückgegeben wird 0, während parseInt("0xf", 16)der von Ihnen erwartete Wert von 15 zurückgegeben wird.
Bart
2
@Joseph the Dreamer und @ hereandnow78: Doppelte Tilde schneidet den Dezimalteil der Zahl ab, während Math.floor die nächstniedrigere Zahl zurückgibt. Sie arbeiten gleich für positive Zahlen, aber Math.floor(-3.5) == -4und ~~-3.5 == -3.
Albin
261

Die ultimative Umrechnungstabelle für beliebige Zahlen: Umrechnungstabelle

Georg
quelle
2
Bitte ergänzen Sie "NaN"diese Tabelle.
Chharvey
Es könnte sich lohnen Zugabe einer sein isNaNSpalte dieser Tabelle: zum Beispiel isNaN("")falsch ist (dh es ist eine Zahl betrachtet), aber parseFloat("")ist NaN, was ein Gotcha sein kann, wenn Sie zu verwenden sind versucht , isNaNdie Eingabe zu bestätigen , bevor es vorbeiparseFloat
retsam
Sie sollten auch '{valueOf: function(){return 42}, toString: function(){return "56"}}'zur Liste hinzufügen . Die gemischten Ergebnisse sind interessant.
Murrayju
3
Die Zusammenfassung der Tabelle lautet also, dass dies +nur eine kürzere Schreibweise ist Number, und die weiteren sind nur verrückte Methoden, die in Randfällen fehlschlagen?
Mihail Malostanidis
Ist [] .undef eine Sache oder ist das nur eine willkürliche Art, undefiniert zu generieren? Über Google kann keine Aufzeichnung von "undef" in Bezug auf JS gefunden werden.
jcairney
10

Die Tabelle in der Antwort von thg435 ist meines Erachtens umfassend, wir können sie jedoch mit den folgenden Mustern zusammenfassen:

  • Unary Plus behandelt nicht alle falschen Werte gleich, aber sie kommen alle falsch heraus.
  • Unary plus sendet truean 1, aber "true"an NaN.
  • Auf der anderen Seite parseIntist es liberaler für Zeichenfolgen, die keine reinen Ziffern sind. parseInt('123abc') === 123, während +Berichte NaN.
  • Numberakzeptiert gültige Dezimalzahlen, während parseIntlediglich alles nach der Dezimalstelle abgelegt wird. parseIntImitiert somit das C-Verhalten, ist aber möglicherweise nicht ideal für die Auswertung von Benutzereingaben.
  • Beide schneiden Leerzeichen in Zeichenfolgen.
  • parseIntDa es sich um einen schlecht gestalteten Parser handelt , werden oktale und hexadezimale Eingaben akzeptiert. Unary Plus nimmt nur hexademisch.

Falsche Werte werden wie Numberfolgt konvertiert, was in C sinnvoll wäre: nullund falsesind beide Null. ""auf 0 zu gehen folgt dieser Konvention nicht ganz, macht aber für mich genug Sinn.

Daher denke ich, wenn Sie Benutzereingaben validieren, hat unary plus für alles das richtige Verhalten, außer dass es Dezimalstellen akzeptiert (aber in meinen realen Fällen bin ich mehr daran interessiert, E-Mail-Eingaben anstelle von Benutzer-IDs abzufangen, der Wert wird komplett weggelassen usw.) parseInt ist zu liberal.

Djechlin
quelle
2
"Unary plus nimmt nur hexadezimal" Meinst du nicht dezimal?
Krillgar
0

Seien Sie vorsichtig, parseInt ist schneller als der unäre Operator + in Node.JS. Es ist falsch, dass + oder | 0 schneller sind, sie sind nur für NaN-Elemente schneller.

Überprüfen Sie dies heraus:

var arg=process.argv[2];

rpt=20000;
mrc=1000;

a=[];
b=1024*1024*1024*1024;
for (var i=0;i<rpt;i++)
 a[i]=Math.floor(Math.random()*b)+' ';

t0=Date.now();
if ((arg==1)||(arg===undefined))
 for (var j=0;j<mrc;j++) for (var i=0;i<rpt;i++) {
  c=a[i]-0;
 }
t1=Date.now();
if ((arg==2)||(arg===undefined)) {
 for (var j=0;j<mrc;j++) for (var i=0;i<rpt;i++) {
  d=a[i]|0;
 }
}
t2=Date.now();
if ((arg==3)||(arg===undefined)) {
 for (var j=0;j<mrc;j++) for (var i=0;i<rpt;i++) {
  e=parseInt(a[i]);
 }
}
t3=Date.now();
 if ((arg==3)||(arg===undefined)) {
 for (var j=0;j<mrc;j++) for (var i=0;i<rpt;i++) {
  f=+a[i];
 }
}
t4=Date.now();

console.log(a[i-1],c,d,e,f);
console.log('Eseguiti: '+rpt*mrc+' cicli');
console.log('parseInt '+(t3-t2));
console.log('|0 '+(t2-t1));
console.log('-0 '+(t1-t0));
console.log('+ '+(t4-t3));
Informate.it
quelle
-3

Berücksichtigen Sie auch die Leistung . Ich war überrascht, dass es parseIntunter iOS unary plus schlägt :) Dies ist nur für Web-Apps mit hohem CPU-Verbrauch hilfreich. Als Faustregel würde ich JS-Optikern empfehlen, jeden JS-Betreiber heutzutage unter dem Gesichtspunkt der mobilen Leistung gegenüber einem anderen zu betrachten.

Also, geh zuerst mobil ;)

Arman McHitarian
quelle
Wie die anderen Beiträge erklären, machen sie ganz andere Dinge, so dass man nicht einfach eins gegen das andere tauschen kann ...
Bergi
@Bergi, richtig, aber sie haben auch viel gemeinsam. Sagen Sie mir nur eine Leistungslösung in JavaScript, die definitiv die einzig richtige Wahl ist? Im Allgemeinen gibt es deshalb Faustregeln für uns. Der Rest ist aufgabenspezifisch.
Arman McHitarian
3
@ArmanMcHitaryan das ist nutzlose Mikrooptimierung und es lohnt sich nicht. Schauen Sie sich diesen Artikel an - fabien.potencier.org/article/8/…
webvitaly
@ Webvitaly, schöner Artikel. Es gibt immer sehr perf-orientierte Leute da draußen, die einfach gerne "den schnellstmöglichen" Code schreiben und in einigen spezifischen Projekten ist das nicht schlecht. Deshalb habe ich "JS Opt-Jungs zu berücksichtigen" erwähnt. das ist natürlich kein MUSS :), aber ich selbst finde es zusätzlich viel lesbarer.
Arman McHitarian
Hast du ein Zitat dafür? Ihr Link ist defekt.
Djechlin