Jaki jest najszybszy sposób konwersji ciągu znaków na liczbę w JavaScript?

122

Dowolna liczba, to liczba. Ciąg wygląda jak liczba, to liczba. Wszystko inne idzie na NaN.

'a' => NaN
'1' => 1
1 => 1
beatak
źródło
To, co jest najszybsze, zależy od optymalizacji w danej implementacji w określonym czasie. Nie ma obiektywnie „najszybszego” sposobu.
I Hate Lazy
2
Co zrobić ze '1a'sznurkiem? Z ' 1'jednym? Innymi słowy, dlaczego najpopularniejsze metody, aby to zrobić ( Number(x)i parseInt(x, 10)) nie są dla Ciebie wystarczające?
raina77ow
Poprzedni test jsperf: jsperf.com/converting-string-to-int/3
epascarello
tutaj dobre porównanie wydajności różnych metod: jsben.ch/#/NnBKM
EscapeNetscape

Odpowiedzi:

192

O ile wiem, są na to 4 sposoby.

Number(x);
parseInt(x, 10);
parseFloat(x);
+x;

Ten szybki test, który zrobiłem, w rzeczywistości zależy od przeglądarek.

http://jsperf.com/best-of-string-to-number-conversion/2

Implicit oznaczony najszybciej w 3 przeglądarkach, ale sprawia, że ​​kod jest trudny do odczytania… Wybierz więc, co chcesz!

beatak
źródło
7
Co ciekawe, Google Analytics (część, którą wklejasz do swojej witryny) wykorzystuje 1*do konwersji daty na numer, która jest podobna do +powyższej. tj. 1*new Date()zamiast +new Date(). Być może jest bardziej czytelny?
Matthew Wilcoxson
1
Myślę, że 1*jest preferowany, ponieważ jest mniej podatny na błędy. Niepożądana zmienna wisząca wcześniej +1nie jest błędem analizy. To sztuczka podobna do używania if (MYCONSTANT == myvar)w C.
Tomas
5
@beatak - obecne optymalizacje wydają się faworyzować metody natywne w przeciwieństwie do niejawnej konwersji. Osiągam najszybszy wynik w przypadku Number () w przeglądarce Chrome 37.0.2062.124 w systemie Windows Server 2008 R2 / 7 i ParseInt () w przeglądarce Firefox 30.0, przy czym niejawne jest najwolniejsze dla obu. Możesz również rozważyć uwzględnienie w teście pływających literałów ciągu w celu ogólnego porównania. Domyślam się, że w niektórych przypadkach może to zmienić kolejność, ponieważ konwersja ciągów na zmiennoprzecinkowe jest zwykle wolniejsza niż konwersja ciągów na int. Sposób, w jaki test jest teraz, polega na konwersji ciągu na int, gdy używana jest Number ().
Nolo
1
Chrome 61.0.3163. Number () jest najszybszy ze wszystkich.
Dmitry Petukhov
70

Można to zrobić na co najmniej 5 sposobów:

Jeśli chcesz konwertować tylko na liczby całkowite, innym szybkim (i krótkim) sposobem jest użycie dwóch bitów nie (tj. Użycie dwóch znaków tyldy):

na przykład

~~x;

Źródła : http://james.padolsey.com/cool-stuff/double-bitwise-not/

Pięć znanych dotychczas sposobów konwertowania ciągu znaków na liczbę ma swoje różnice (istnieje więcej działających operatorów bitowych, ale wszystkie dają ten sam wynik co ~~). Ten JSFiddle pokazuje różne wyniki, których można oczekiwać w konsoli debugowania: http://jsfiddle.net/TrueBlueAussie/j7x0q0e3/22/

var values = ["123",
          undefined,
          "not a number",
          "123.45",
          "1234 error",
          "2147483648",
          "4999999999"
          ];

for (var i = 0; i < values.length; i++){
    var x = values[i];

    console.log(x);
    console.log(" Number(x) = " + Number(x));
    console.log(" parseInt(x, 10) = " + parseInt(x, 10));
    console.log(" parseFloat(x) = " + parseFloat(x));
    console.log(" +x = " + +x);
    console.log(" ~~x = " + ~~x);
}

Konsola debugowania:

123
  Number(x) = 123
  parseInt(x, 10) = 123
  parseFloat(x) = 123
  +x = 123
  ~~x = 123
undefined
  Number(x) = NaN
  parseInt(x, 10) = NaN
  parseFloat(x) = NaN
  +x = NaN
  ~~x = 0
null
  Number(x) = 0
  parseInt(x, 10) = NaN
  parseFloat(x) = NaN
  +x = 0
  ~~x = 0
"not a number"
  Number(x) = NaN
  parseInt(x, 10) = NaN
  parseFloat(x) = NaN
  +x = NaN
  ~~x = 0
123.45
  Number(x) = 123.45
  parseInt(x, 10) = 123
  parseFloat(x) = 123.45
  +x = 123.45
  ~~x = 123
1234 error
  Number(x) = NaN
  parseInt(x, 10) = 1234
  parseFloat(x) = 1234
  +x = NaN
  ~~x = 0
2147483648
  Number(x) = 2147483648
  parseInt(x, 10) = 2147483648
  parseFloat(x) = 2147483648
  +x = 2147483648
  ~~x = -2147483648
4999999999
  Number(x) = 4999999999
  parseInt(x, 10) = 4999999999
  parseFloat(x) = 4999999999
  +x = 4999999999
  ~~x = 705032703

Te ~~xwyniki wersja numeru w „więcej” przypadkach, gdy inni często skutkują undefined, ale to nie z powodu nieprawidłowych wejścia (np powróci 0, jeśli ciąg zawiera znaki spoza numerycznych po ważnego numeru).

Przelewowy

Uwaga: przepełnienie liczby całkowitej i / lub obcięcie bitów może wystąpić w ~~przypadku innych konwersji, ale nie. Chociaż wprowadzanie tak dużych wartości jest niezwykłe, musisz być tego świadomy. Przykład zaktualizowany w celu uwzględnienia znacznie większych wartości.

Niektóre testy wydajności wskazują, że standard parseInti parseFloatfunkcje są w rzeczywistości najszybszymi opcjami, prawdopodobnie wysoce zoptymalizowanymi przez przeglądarki, ale wszystko zależy od Twoich wymagań, ponieważ wszystkie opcje są wystarczająco szybkie : http://jsperf.com/best-of-string-to -konwersja liczby / 37

Wszystko zależy od konfiguracji testów perf, ponieważ niektóre z nich pokazują, że parseInt / parseFloat jest znacznie wolniejsze.

Moja teoria brzmi:

  • Kłamstwa
  • Cholerne linie
  • Statystyka
  • Wyniki JSPerf :)
Gone Coding
źródło
3
Uważaj na liczby większe niż 2147483647. np . ~~4294967296Zwraca 0.
Joseph Goh
@JosephGoh: Kiedy nadarzy się okazja, rozszerzę wyniki o przepełnienie zakresu int. Ogólnie rzecz biorąc, jeśli liczby są tak duże, masz bardzo specjalny interfejs, więc musisz być świadomy przepełnienia. Pozdrowienia
Gone Coding
@JosephGoh: Co ciekawe, w Chrome nie dostajesz 0, dostajesz liczby ujemne po wartości maksymalnej ze znakiem. Wtedy wydaje się po prostu porzucić dodatkowe bity, gdy przekroczysz wartość unsigned int max. np. „4999999999” => 705032703
kodowania
8

Poprzedź ciąg z +operatorem.

console.log(+'a') // NaN
console.log(+'1') // 1
console.log(+1) // 1
Pratheep
źródło
7

Szybkim sposobem na przekonwertowanie ciągów znaków na liczbę całkowitą jest użycie bitów lub tak:

x | 0

Chociaż zależy to od tego, w jaki sposób zostanie wdrożony, w teorii powinien być stosunkowo szybki (przynajmniej tak szybki, jak +x), ponieważ najpierw będzie rzutował xna liczbę, a następnie wykona bardzo wydajne lub.

user3784814
źródło
Tak, ale uważam, że ta technika skraca duże liczby całkowite, to jest bardzo złe. Należy zauważyć, że można również użyć zamiast Math.floor (), ale z tym samym problemem.
Jean,
Oto jsperf różnych operatorów bitowych w połączeniu z metodami z pierwszej odpowiedzi. Losowo zmieniłem kolejność, ponieważ stwierdziłem, że niektóre przeglądarki optymalizują następny test na podstawie podobnego kodu z poprzedniego testu. W przeciwieństwie do odpowiedzi udzielającej pierwszej odpowiedzi stwierdziłem, że domniemana była najgorsza metoda.
Pluto,
4

Oto prosty sposób na zrobienie tego: var num = Number (str); w tym przykładzie str jest zmienną zawierającą ciąg. Możesz przetestować i zobaczyć, jak to działa, otwórz: narzędzia programistyczne Google chrome , a następnie przejdź do konsoli i wklej następujący kod. przeczytaj komentarze, aby lepiej zrozumieć, jak przebiega konwersja.

// Here Im creating my variable as a string
var str = "258";


// here im printing the string variable: str
console.log ( str );


// here Im using typeof , this tells me that the variable str is the type: string
console.log ("The variable str is type: " + typeof str);


// here is where the conversion happens
// Number will take the string in the parentesis and transform it to a variable num as type: number
var num = Number(str);
console.log ("The variable num is type: " + typeof num);
Edmundo
źródło
4

Uważam, że num * 1jest to proste, przejrzyste i działa dla liczb całkowitych i zmiennoprzecinkowych ...

Daniel Smith
źródło
3

Prawdopodobnie nie jest to tak szybkie, ale ma dodatkową zaletę polegającą na upewnieniu się, że numer ma co najmniej określoną wartość (np. 0) lub co najwyżej określoną wartość:

Math.max(input, 0);

Jeśli chcesz zapewnić minimalną wartość, zwykle to robisz

var number = Number(input);
if (number < 0) number = 0;

Math.max(..., 0) oszczędza ci pisania dwóch stwierdzeń.

Dan Dascalescu
źródło
Dlaczego nie używać Math.abs(input)? Konwertuje również łańcuchy na liczby dodatnie i zapisuje kilka dodatkowych znaków.
Aaron Gillion
1
@AaronGillion: Math.max (-5, 0) zwróci 0; Math.abs (-5) zwróci 5. Zależy to od przypadku użycia, który ma większy sens.
Dan Dascalescu
1
Och, ups, tak, mój przypadek użycia był zupełnie inny, niezależnie od tego, jak późno napisałem ten komentarz.
Aaron Gillion,
Jeśli inputnie można przekonwertować na numer, otrzymaszNaN
Domas Mar
0

Możesz spróbować użyć UnitOf , biblioteki pomiarów i konwersji typów danych, którą właśnie oficjalnie wydaliśmy! UnitOf jest super szybki, mały i skuteczny w konwersji dowolnego typu danych bez zgłaszania błędu lub wartości null / undefined. Zdefiniowane wartości domyślne lub wartości domyślne UnitOf są zwracane, gdy konwersja zakończy się niepowodzeniem.

//One liner examples
UnitOf.DataType("12.5").toFloat(); //12.5 of type Float is returned. 0 would be returned if conversion failed.
UnitOf.DataType("Not A Num").toInt(10); //10 of type Int is returned as the conversion failed.

//Or as a variable
var unit = UnitOf.DataType("12.5");
unit.toInt(5); //12.5 of type Float is returned. 5 would be returned if the conversion failed.
unit.toFloat(8); // 12 of type Int is returned. 8 would be returned if the conversion failed.
Digidemic
źródło
0

Najszybszym sposobem jest użycie -0:

const num = "12.34" - 0;
Arturas
źródło