Javascript'teki sıralama özellikleri bozuk


15

Özel anahtarlar ile bir dizi olarak davranan bir JavaScript nesnesi ile döngü gerekir. Bunun tam olarak desteklenmediğini biliyorum, çünkü özelliklerin içsel bir düzeni yoktur, ancak özellikleri her zaman yeniden sıraladığım için, bu yaklaşımı basit ve güvenilir buldum ... şimdiye kadar.

Anahtarlar sayı veya sayı olarak dökülebilecek dizeler olduğunda sorun oluşur.

Bu kodu çalıştırdığımda:

var test1 = {4294966222:"A",4294966333:"A",4294966111:"A"};
var test2 = {4294968222:"A",4294968333:"A",4294968111:"A"};
        
for (var k in test1) {console.log(k);}
console.log("---");
for (var k in test2) {console.log(k);}

çıktı:

4294966111
4294966222
4294966333
---
4294968222
4294968333
4294968111

Bunun anlamı:

  • (test1) anahtarlar 2 ^ 32'nin (4,294,967,296) altındaysa, otomatik olarak yeniden sıralanırlar, en küçüğü
  • (test2) anahtarlar 2 ^ 32'nin üzerindeyse, yeniden sıralanmazlar.

Soru şudur: bu neden oluyor?

Test ettiğim tüm tarayıcılar (Google Chrome 79.0, Mozilla Firefox 71.0, Microsoft Edge 44.18362, Internet Explorer 11.535) bu çıktıyı kabul ettiğinden, bazı resmi özellikler olmalıdır.

Güncelleme

Bir eşik sorunu olduğunu anlamadan önce birçok sayıyı test ettim. 2,3,1 dizisinin aynı şekilde sıralanan üç zaman damgasından farklı davrandığı garip buldum.


tahminim hash kodunun nasıl hesaplandığıdır, ancak sorunuza gerçek bir cevap değildir.
Mario Vernari

1
Kelimenin gerçek konuşma dilinde kırıldığını düşünmüyorum, geliştiriciyi kontrol edebildiğiniz için keyfi olarak çalıştığından değerlerin sıra ile yineleneceğini garanti etmiyorlar. Mozilla.org/tr- / JavaScript / Reference /… "Not: for ... in, dizin sırasının önemli olduğu bir Dizi üzerinde yineleme yapmak için kullanılmamalıdır." Sadece koleksiyondaki her öğe üzerinde yinelemeyi garanti ederler. ForEach gibi bir şey aslında artan düzende kateden öğeleri tarafından dikkate sırasını sürer ecma-international.org/ecma-262/5.1/#sec-15.4.4.18
Mr.Toxy

Kayıt için, sorunu doğrudan günlüğe kaydederek test1ve görebilirsiniz test2. "Sorun" spec V8 uygulamasında anahtar önbellekleme olduğunu düşünüyorum.
Seblor

Mülk adınızın 2 ^ 32 altında, dahili mülk referanslarına benzer şekilde tesadüfen sipariş edilmesi daha fazladır. Tanım gereği sıralı olmadıklarından ve nesnenin doğasında olan özellikler içerebileceğinden, nesne özelliklerinin sırasına güvenebilir ve güvenmemelisiniz. Nesnenizi her zaman bir diziye yayınlayın / eşleyin, diziyi sıralayın, ardından sipariş önemliyse onu döngüden geçirin.
user3154108

1
@ Mr.Toxy Çünkü bu özellikleri 4294968333ve 4294968111daha büyük 2 ** 32(ki 4294967296). Yani, dizi göstergeleri değiller, bu yüzden sayısal düzende değil, özellik oluşturma düzeninde yineleniyorlar - beklendiği gibi kemanda tam olarak yaptıkları şey bu. (Cevabımı gör)
CertainPerformance

Yanıtlar:


4

Bu bekleniyor. Başına şartname , özelliklerini üzerinde dolaşır yöntem OrdinaryOwnPropertyKeys, yapar:

  1. Bir dizi dizini olan O'nun her kendi özellik anahtarı P için, artan sayısal dizin sırasında,

    a. P tuşlarını son tuş olarak ekleyin.

  2. Bir String olan ancak bir dizi dizini olmayan O'nun her kendi özellik anahtarı P için, artan özellik oluşturma kronolojik sırasına göre,

    a. P tuşlarını son tuş olarak ekleyin.

Artan sayısal sıra yalnızca dizi göstergesi olan özellikler için geçerlidir.

Peki, "dizi indeksi" nedir? Şuna bak :

Bir tamsayı dizini, kanonik bir sayısal Dize (bkz. 7.1.21) olan ve sayısal değeri +0 veya pozitif bir tam sayı ≤ 2 ^ 53 - 1 olan bir Dize değerli özellik anahtarıdır. Bir dizi dizini, sayısal değeri olan bir tam sayı dizinidir i değeri +0 ≤ i <2 ^ 32-1 aralığındadır.

Bu nedenle, 2 ^ 32'den büyük sayısal özellikler dizi göstergeleri değildir ve bu nedenle özellik oluşturma sırasına göre yinelenir. Bununla birlikte, dizi göstergelerden daha küçük 2^32 olan sayısal özellikler ve artan sırayla yinelenir.

Yani mesela:

1: Dizi dizini, sayısal olarak yinelenecek

10: Dizi dizini, sayısal olarak yinelenecek

4294968111: Özellik oluşturma sırasında dizi göstergeleri bittikten sonra2 ** 32 yinelenecek

9999999999999: Özellik oluşturma sırasında dizi göstergeleri bittikten sonra2 ** 32 yinelenecek

Ayrıca, yaygın inanışın aksine, mülkiyet yineleme düzeni, unutmayın edilir , hem de şartname ile sayesinde garanti için-de yineleme önerisi evre 4 olduğunu.


2

Bu, bir nesnenin anahtarlarının geçişi ile ilgilidir.

ES6 özelliklerine göre:

9.1.12 [[OwnPropertyKeys]] ( )

When the [[OwnPropertyKeys]] internal method of O is called the following steps are taken:

    Let keys be a new empty List.
    For each own property key P of O that is an integer index, in ascending numeric index order
        Add P as the last element of keys.
    For each own property key P of O that is a String but is not an integer index, in property creation order
        Add P as the last element of keys.
    For each own property key P of O that is a Symbol, in property creation order
        Add P as the last element of keys.
    Return keys.

http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys

Bu, eğer bir anahtarın değeri işaretsiz bir 53 bit sayıya dönüştürülürse aynı kalırsa ve geri artan artan sırada sıralanmış bir tamsayı dizini olarak kabul edilir .

Bu başarısız olursa, nesneye eklenme şekli sıralanan bir dize anahtarı olarak kabul edilir.

Buradaki yakalama, tüm büyük tarayıcıların bu spesifikasyonu henüz takip etmediği ve bunun yerine pozitif bir sayıyla sınırlandırılmış bir dizi dizini kullanmasıdır 2 ^ 32-1. Bu sınırın üstündeki her şey aslında bir dize anahtarıdır.

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.