Array'e filtre yöntemi ekleyen Mozilla koduna bakıyordum ve kafamı karıştıran bir kod satırı vardı.
var len = this.length >>> 0;
Daha önce JavaScript'te >>> kullanıldığını hiç görmemiştim.
Nedir ve ne işe yarar?
Array'e filtre yöntemi ekleyen Mozilla koduna bakıyordum ve kafamı karıştıran bir kod satırı vardı.
var len = this.length >>> 0;
Daha önce JavaScript'te >>> kullanıldığını hiç görmemiştim.
Nedir ve ne işe yarar?
Array.prototype.push
/ Array.prototype.pop
- hexmen.com/blog/2006/12/push-and-pop'a çevirerek (testleri o yapmış olsa da, haha).
Yanıtlar:
Yalnızca Sayı olmayanları Sayıya dönüştürmekle kalmaz, aynı zamanda onları 32 bitlik işaretsiz tams olarak ifade edilebilen Sayılara dönüştürür.
JavaScript'in Sayılar çift duyarlıklı yüzer (*), bit operatörleri olmasına rağmen ( <<
, >>
, &
, |
ve ~
) 32 bit tamsayılar üzerinde operasyonlar açısından tanımlanır. Bitsel işlem yapmak, sayıyı 32 bitlik işaretli int'e dönüştürür, hesaplamayı yapmadan ve ardından tekrar Sayı'ya dönüştürmeden önce tüm kesirleri ve 32'den daha yüksek basamaklı bitleri kaybeder.
Bu nedenle, 0 bitlik sağa kaydırma gibi gerçek bir etkisi olmayan bit düzeyinde bir işlem yapmak, >>0
bir sayıyı yuvarlamanın ve 32 bitlik aralıkta olmasını sağlamanın hızlı bir yoludur. Ek olarak, üçlü >>>
operatör, işaretsiz işlemini yaptıktan sonra, hesaplamasının sonuçlarını, diğerlerinin yaptığı işaretli tamsayı yerine işaretsiz bir tam sayı olarak Sayı'ya dönüştürür, böylece negatifleri 32-bit-ikinin-tamamlayıcısına dönüştürmek için kullanılabilir. büyük bir Sayı olarak sürüm. Kullanmak >>>0
, 0 ile 0xFFFFFFFF arasında bir tam sayıya sahip olmanızı sağlar.
Bu durumda bu yararlıdır çünkü ECMAScript, Array dizinlerini 32 bitlik işaretsiz ints cinsinden tanımlar. Dolayısıyla array.filter
, ECMAScript Fifth Edition standardının söylediği şeyi tam olarak kopyalayacak şekilde uygulamaya çalışıyorsanız , sayıyı 32-bit işaretsiz int'e bu şekilde çevirirsiniz.
(Gerçekte küçük pratik şuna gerek yoktur umarım insanlar olmamız gidiş değildir kadar array.length
için 0.5
, -1
, 1e21
veya 'LEMONS'
. Ama hiç belli olmaz yani bu, Bahsettiğimiz JavaScript yazarlar ise ...)
Özet:
1>>>0 === 1
-1>>>0 === 0xFFFFFFFF -1>>0 === -1
1.7>>>0 === 1
0x100000002>>>0 === 2
1e21>>>0 === 0xDEA00000 1e21>>0 === -0x21600000
Infinity>>>0 === 0
NaN>>>0 === 0
null>>>0 === 0
'1'>>>0 === 1
'x'>>>0 === 0
Object>>>0 === 0
(*: yüzer gibi davranıyor olarak tanımlanıyorlar. Bazı JavaScript motorlarının, yapabildiğinde performans nedenlerinden ötürü gerçekten ints kullanması beni şaşırtmaz. Avantajı.)
RangeError: invalid array length
.
Array.prototype.filter.call
) çağrılmasına izin verir , bu nedenle array
aslında gerçek Array
olmayabilir: başka bir kullanıcı tanımlı sınıf olabilir. (Ne yazık ki, güvenilir bir şekilde bir NodeList olamaz, ki bunu gerçekten yapmak isteyeceğiniz zaman, çünkü bu bir ana bilgisayar nesnesi. Bunu gerçekçi bir şekilde arguments
sözde Array olarak yapabileceğiniz tek yer bırakıyor .)
if
açıklamada değerlendirmenin sol tarafı bir int olmadığını belirlemeye çalışırken bunun için böyle görünür? 'lemons'>>>0 === 0 && 0 >>>0 === 0
doğru olarak değerlendiriliyor? limon açıkça bir kelime olsa bile ..?
İşaretsiz sağa kaydırma operatörü, özelliğin işaretsiz 32 bitlik bir tamsayı olmasını sağlamak için, Mozilla dizisinin tüm ekstra yöntem uygulamalarında kullanılır .length
length
Dizi nesnelerin özelliği olduğu genel olarak tarif edilen tarifnamede olarak:
Her Array nesnesinin, değeri her zaman 2 32'den küçük negatif olmayan bir tam sayı olan bir length özelliği vardır .
Bu operatör, bunu başarmanın en kısa yoludur, dahili olarak dizi yöntemleri işlemi kullanır ToUint32
, ancak bu yöntem erişilebilir değildir ve uygulama amaçları için belirtimde mevcuttur.
Mozilla dizi ekstraları uygulamaları ECMAScript 5 uyumlu olmaya çalışır , Array.prototype.indexOf
yöntemin açıklamasına bakın (§ 15.4.4.14):
1. ToObject çağrısının bu değeri geçmesinin sonucu O olsun argüman olarak. 2. lenValue, O'nun [[Get]] dahili yöntemini çağırmanın sonucu olsun. "uzunluk" argümanı. 3. len ToUint32 (lenValue) olsun . ....
Gördüğünüz gibi, ToUint32
ES3 uygulamasında ES5 spesifikasyonuna uymak için yöntemin davranışını yeniden oluşturmak istiyorlar ve daha önce de söylediğim gibi, imzasız sağa kaydırma operatörü en kolay yoldur.
ToUint32
bana biraz gereksiz görünüyor.
Array.prototype
Yöntemlerin çoğunun kasıtlı olarak jenerik olduğunu , örneğin dizi benzeri nesnelerde kullanılabileceğini unutmayın Array.prototype.indexOf.call({0:'foo', 1:'bar', length: 2}, 'bar') == 1;
. arguments
Nesne aynı zamanda iyi bir örnektir. İçin saf dizi nesneler, bu türünü değiştirmek imkansız length
onlar special uygulamak çünkü, mülkiyet [[Put
bir atama yapılır]] dahili yöntem ve length
mülkiyet, yeniden dönüştürülmüş olan ToUint32
ve diğer eylemler yukarıdaki indeksler silme gibi alınır yeni uzunluk ...
Bu, işaretsiz sağ bit kaydırma operatörüdür. Bununla işaretli sağ bit kaydırma operatörü arasındaki fark , işaretsiz sağ bit kaydırma operatörünün ( >>> ) soldan sıfırlarla doldurması ve işaretli sağ bit kaydırma operatörünün ( >> ) işaret biti ile doldurmasıdır. kaydırıldığında sayısal değerin işaretini korumak.
>>>
tek terimli +
olmayan bir tam sayıya dönüştürür .
Driis , operatörün ne olduğunu ve ne yaptığını yeterince açıkladı. İşte arkasındaki anlam / neden kullanıldığı:
Tarafından herhangi bir yöne kaydırmak 0
döndürür orijinal sayı yapar ve döküm olacak null
kadar 0
. Görünüşe göre baktığınız örnek kod, tanımlanmamış olsa bile bunun sayısal this.length >>> 0
olmasını sağlamak için kullanıyor . len
this.length
Pek çok insan için bitsel işlemler belirsizdir (ve Douglas Crockford / jslint bu tür şeylerin kullanılmamasını önerir). Yapmanın yanlış olduğu anlamına gelmez, ancak kodu daha okunaklı hale getirmek için daha uygun ve tanıdık yöntemler vardır. Sağlamak için daha net bir yol len
olduğunu 0
aşağıdaki iki yöntemden birini olduğunu.
// Cast this.length to a number
var len = +this.length;
veya
// Cast this.length to a number, or use 0 if this.length is
// NaN/undefined (evaluates to false)
var len = +this.length || 0;
NaN
Örneğin +{}
... İkisini birleştirmek muhtemelen en iyisidir:+length||0
>>>
olan işaretsiz sağa kaydırma operatörü ( bkz. JavaScript 1.5 şartnamenin 76 ), karşıt olarak >>
, imza sağ shift operatör.
>>>
negatif sayıları kaydırmanın sonuçlarını değiştirir çünkü kaydırma sırasında işaret bitini korumaz . Bunun sonuçları, bir tercümandan örnekle anlaşılabilir:
$ 1 >> 0
1
$ 0 >> 0
0
$ -1 >> 0
-1
$ 1 >>> 0
1
$ 0 >>> 0
0
$ -1 >>> 0
4294967295
$(-1 >>> 0).toString(16)
"ffffffff"
$ "cabbage" >>> 0
0
Dolayısıyla, muhtemelen burada yapılması amaçlanan, "cabbage"
yukarıdaki örnekte olduğu gibi uzunluğu veya uzunluk tanımsızsa veya bir tam sayı değilse 0'ı elde etmektir . Sanırım bu durumda bunun this.length
asla olmayacağını varsaymak güvenli < 0
. Yine de, bu örneğin iki nedenden ötürü çirkin bir hack olduğunu iddia ediyorum :
<<<
Negatif sayılar kullanıldığında, yukarıdaki örnekte muhtemelen amaçlanmayan (veya meydana gelmesi muhtemel) bir yan etkinin davranışı .
Bu sorunun varlığının da doğruladığı gibi , kodun amacı açık değildir .
En iyi uygulama, performans kesinlikle kritik olmadığı sürece muhtemelen daha okunabilir bir şey kullanmaktır:
isNaN(parseInt(foo)) ? 0 : parseInt(foo)
-1 >>> 0
olabilir mi ve eğer öyleyse, 4294967295'e kaydırmak gerçekten arzu edilir mi? Görünüşe göre bu, döngünün gerekenden birkaç kez daha fazla çalışmasına neden olacak.
this.length
bilmek imkansız. Herhangi bir "mantıklı" uygulama için, bir dizenin uzunluğu asla negatif olmamalıdır, ancak o zaman biri "mantıklı" bir ortamda this.length
her zaman bir integral sayı döndüren bir özelliğin varlığını varsayabileceğimizi iddia edebilir .
İki sebep:
>>> sonucu bir "integral" dir
tanımsız >>> 0 = 0 (JS, LFS'yi sayısal bağlama zorlayacağından, bu "foo" >>> 0 vb. için de çalışacaktır)
JS'deki sayıların çiftin dahili temsiline sahip olduğunu unutmayın. Bu, uzunluk için temel girdi mantığının "hızlı" bir yoludur.
Bununla birlikte , -1 >>> 0 (oops, muhtemelen istenen uzunluk değil!)
Aşağıdaki örnek Java Kodu iyi açıklıyor:
int x = 64;
System.out.println("x >>> 3 = " + (x >>> 3));
System.out.println("x >> 3 = " + (x >> 3));
System.out.println(Integer.toBinaryString(x >>> 3));
System.out.println(Integer.toBinaryString(x >> 3));
Çıktı aşağıdaki gibidir:
x >>> 3 = 536870904
x >> 3 = -8
11111111111111111111111111000
11111111111111111111111111111000