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

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


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!


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 :)

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

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.


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);

4

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


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ń.


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.

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.