JavaScript'te String'i Sayıya dönüştürmenin en hızlı yolu nedir?


122

Herhangi bir sayı, sayıdır. String bir sayıya benziyor, bu sayı. Diğer her şey, NaN gider.

'a' => NaN
'1' => 1
1 => 1

En hızlı olan, belirli bir zamanda belirli bir uygulamadaki optimizasyonlara bağlıdır. Nesnel olarak "en hızlı" yol yoktur.
I Hate Lazy

2
İp ile ne yapılmalı '1a'? Biriyle ' 1'mi? Başka bir deyişle, neden bunu yapmak için en yaygın yöntemler ( Number(x)ve parseInt(x, 10)) sizin için yeterli değil?
raina77ow


burada farklı yöntemlerin iyi bir performans karşılaştırması: jsben.ch/#/NnBKM
EscapeNetscape

Yanıtlar:


192

Bildiğim kadarıyla bunu yapmanın 4 yolu var.

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

Yaptığım bu hızlı test ile aslında tarayıcılara bağlı.

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

Implicit 3 tarayıcıda en hızlı olarak işaretlendi, ancak kodun okunmasını zorlaştırıyor… Öyleyse, ne hissediyorsan seç!


7
İlginç bir şekilde Google Analytics (web sitenize yapıştırdığınız kısım) 1*, +yukarıdakine benzer şekilde tarih-sayı dönüştürme için kullanır . yani 1*new Date()yerine +new Date(). Muhtemelen daha okunabilir mi?
Matthew Wilcoxson

1
Daha 1*az hataya meyilli olduğu için tercih edildiğini düşünüyorum . Önceden istenmeyen sarkan değişken +1bir ayrıştırma hatası değildir. Bu kullanmaya benzer bir hile if (MYCONSTANT == myvar)de C.
Tomas

5
@beatak - Mevcut optimizasyonlar, örtük dönüştürmenin aksine yerel yöntemleri tercih ediyor gibi görünüyor. Windows Server 2008 R2 / 7'de Chrome 37.0.2062.124'te Number () için ve Firefox 30.0'da ParseInt () için en hızlı şekilde alıyorum, örtük olarak her ikisi için de en yavaş olanı. Ayrıca, genel karşılaştırma için sınamaya dize değişmez kayan değerler eklemeyi düşünebilirsiniz. Tahminim, bazı durumlarda sırayı değiştirebileceğidir çünkü dizeden float'a dönüşüm genellikle dizeden int'e dönüşümden daha yavaştır. Testin şu anki şekli, Number () kullanıldığında bir dizeden int dönüşümüne geçiyor.
Nolo

1
Chrome 61.0.3163. Number () en hızlısıdır.
Dmitry Petukhov

70

Bunu yapmanın en az 5 yolu vardır:

Yalnızca tamsayılara dönüştürmek istiyorsanız, başka bir hızlı (ve kısa) yol, çift ​​bitli değil (yani iki tilde karakteri kullanmaktır):

Örneğin

~~x;

Referans: http://james.padolsey.com/cool-stuff/double-bitwise-not/

Bir dizeyi bir sayıya dönüştürmenin şu ana kadar bildiğim 5 yaygın yolunun hepsinin farklılıkları vardır (çalışan daha fazla bitsel işleç vardır, ancak hepsi aynı sonucu verir ~~). Bu JSFiddle, hata ayıklama konsolunda bekleyebileceğiniz farklı sonuçları gösterir: 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);
}

Hata ayıklama konsolu:

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

~~xVersiyon diğerleri genellikle neden "daha" durumlarda, bir dizi sonuçları undefined, ancak geçersiz giriş için başarısız (örneğin o dönecektir 0dize olmayan sayı karakterler içeriyorsa sonra geçerli bir sayı).

taşma

Lütfen dikkat: Tamsayı taşması ve / veya bit kesilmesi ~~, diğer dönüştürmelerle birlikte meydana gelebilir , ancak bu gerçekleşmeyebilir. Bu kadar büyük değerler girmek alışılmadık bir durum olsa da, bunun farkında olmanız gerekir. Örnek, çok daha büyük değerler içerecek şekilde güncellendi.

Bazı Perf testleri, standart parseIntve parseFloatişlevlerin aslında en hızlı seçenekler olduğunu ve muhtemelen tarayıcılar tarafından yüksek oranda optimize edildiğini gösteriyor, ancak tüm seçenekler yeterince hızlı olduğu için bunların tümü sizin gereksiniminize bağlı : http://jsperf.com/best-of-string-to -sayısı dönüşüm / 37

Bazıları parseInt / parseFloat'ı çok daha yavaş olacak şekilde gösterdiğinden, bu tamamen perf testlerin nasıl yapılandırıldığına bağlıdır.

Benim teorim:

  • Yalanlar
  • Darn hatları
  • İstatistik
  • JSPerf sonuçları :)

3
2147483647'den büyük sayılar için gerçekten dikkatli olun . Örneğin: ~~4294967296döner 0.
Joseph Goh

@JosephGoh: Bir şansım olduğunda sonuçları int aralık taşmasını içerecek şekilde genişleteceğim. Genel olarak, sayılar bu kadar büyükse, devam eden çok özel bir arayüzünüz varsa, taşmanın farkında olmanız gerekir. Cheers
Gone Coding

@JosephGoh: İlginç bir şekilde, Chrome'da 0'lar almazsınız, işaretli maksimum değerin ötesinde negatif sayılar alırsınız. Ardından, işaretsiz int max değerini aştığınızda fazladan bitleri düşürüyor gibi görünür. ör. "4999999999" => 705032703
Kodlanmaya Gitti

8

Dizenin önüne +işleç ekleyin .

console.log(+'a') // NaN
console.log(+'1') // 1
console.log(+1) // 1

7

Dizeleri bir tam sayıya dönüştürmenin hızlı bir yolu, bitsel kullanmaktır veya bunun gibi:

x | 0

Nasıl uygulandığına bağlı olsa da, teoride göreceli olarak hızlı (en az +xonun kadar hızlı ) olmalıdır çünkü önce xbir sayıya atılacak ve sonra çok verimli veya.


Evet, ama bu tekniğin büyük tam sayıları kısalttığına inanıyorum, bu oldukça kötü. Dikkat edilmesi gereken, Math.floor () yerine de kullanılabilir, ancak aynı sorunla.
Jean

Burada , ilk yanıttaki yöntemlerle birlikte çeşitli bitsel operatörlerden oluşan bir jsperf var . Sırayı rastgele hale getirdim çünkü bazı tarayıcıların bir sonraki testi önceki testteki benzer koda göre optimize edeceğini öğrendim. En iyi yanıtlayanın aksine, örtük olanın en kötü yöntem olduğunu buldum.
Plüton

4

İşte bunu yapmanın basit yolu: var num = Number (str); bu örnekte str , dizeyi içeren değişkendir. Nasıl çalıştığını test edebilir ve açık olarak görebilirsiniz: Google chrome geliştirici araçları , ardından konsola gidin ve aşağıdaki kodu yapıştırın. Dönüşümün nasıl yapıldığını daha iyi anlamak için yorumları okuyun.

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

Bunun num * 1basit, net ve tamsayılar ve kayan değerler için işe yaradığını görüyorum


3

Bu muhtemelen o kadar hızlı değildir, ancak numaranızın en azından belirli bir değer (ör. 0) veya en fazla belirli bir değer olduğundan emin olmanın ek yararı vardır:

Math.max(input, 0);

Minimum bir değer sağlamanız gerekiyorsa, genellikle

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

Math.max(..., 0) sizi iki cümle yazmaktan kurtarır.


Neden kullanmıyorsun Math.abs(input)? Ayrıca dizeleri pozitif sayılara dönüştürür ve fazladan birkaç karakter kaydeder.
Aaron Gillion

1
@AaronGillion: Math.max (-5, 0) 0 döndürür; Math.abs (-5) 5 döndürecektir. Bu daha mantıklı olan kullanım durumuna bağlıdır.
Dan Dascalescu

1
Oh, whoops, evet, o yorumu yazdıysam gece geç saatte kullanım durumum çok farklıydı.
Aaron Gillion

Eğer inputsayıya dönüştürülemez alırsınızNaN
Domas Mar

0

Resmi olarak yayınladığımız bir ölçüm ve veri türü dönüştürme kitaplığı olan UnitOf'u kullanmayı deneyebilirsiniz ! UnitOf süper hızlıdır, boyutu küçüktür ve herhangi bir veri türünü hata veya boş / tanımsız atmadan dönüştürmede etkilidir. Tanımladığınız varsayılan değerler veya UnitOf'un varsayılanları, bir dönüştürme başarısız olduğunda döndürülür.

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

0

En hızlı yol -0 kullanmaktır:

const num = "12.34" - 0;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.