“For (… in…)” döngüsünde öğe sırası


205

Javascript'teki "for… in" döngüsü, hashtables / elements üzerinden bildirildikleri sırayla gerçekleşiyor mu? Sırayla yapmayan bir tarayıcı var mı?
Kullanmak istediğim nesne bir kez beyan edilecek ve asla değiştirilmeyecektir.

Varsayalım:

var myObject = { A: "Hello", B: "World" };

Ve bunları şu alanlarda da kullanıyorum:

for (var item in myObject) alert(item + " : " + myObject[item]);

En iyi tarayıcılarda 'A: "Merhaba"' nun her zaman 'B: "Dünya"' dan önce gelmesini bekleyebilir miyim?


61
Çünkü sadece potansiyel tarayıcıların ve varyantların bir alt kümesini test ediyor olacaklardı. Gelecekteki tarayıcılardan bahsetmiyorum bile. Başarısız olmayan bir testin herhangi bir beton kanıtı sağladığını varsaymak açıktır.
James Hughes

6
Kendi sınırlı javascript yeteneğimin SO kalabalığından daha iyi olacağından şüpheliyim. Ayrıca kim orada garip tarayıcı pusuda biliyor? Cevapta GChrome'un basit örnek durumumda görünmeyecek bir hataya sahip olduğunu görebilirsiniz.
chakrit


Yanıtlar:


214

John Resig'den alıntı :

Şu anda tüm büyük tarayıcılar, bir nesnenin özellikleri tanımlandıkları sırayla döngü yapmaktadır. Chrome, birkaç durum haricinde de bunu yapıyor. [...] Bu davranış, ECMAScript belirtimi tarafından açıkça tanımsız bırakılmıştır. ECMA-262'de bölüm 12.6.4:

Özellikleri numaralandırma mekaniği ... uygulamaya bağlıdır.

Ancak, spesifikasyon uygulamadan oldukça farklıdır. ECMAScript'in tüm modern uygulamaları, nesne özellikleri aracılığıyla tanımlandıkları sırayla yinelenir. Bu nedenle Chrome ekibi bunu bir hata olarak değerlendirdi ve düzeltecek.

Tüm tarayıcılar , sayısal olmayan her mülk adı için yapılan Chrome ve Opera hariç tanım sırasına uyar. Bu iki tarayıcıda, özellikler ilk sayısal olmayan özelliğin önüne sırayla çekilir (bu, dizilerin nasıl uygulandıklarıyla ilgilidir). Sipariş de aynıdır Object.keys.

Bu örnek ne olacağını açıkça belirtmelidir:

var obj = {
  "first":"first",
  "2":"2",
  "34":"34",
  "1":"1",
  "second":"second"
};
for (var i in obj) { console.log(i); };
// Order listed:
// "1"
// "2"
// "34"
// "first"
// "second"

Bunun teknik özellikleri, bunun herhangi bir zamanda değişebileceğinden daha az önemlidir. Bu şekilde kalan şeylere güvenmeyin.

Kısaca: Sipariş sizin için önemliyse bir dizi kullanın.


3
Pek sayılmaz. Chrome, diğer tarayıcılarla aynı siparişi uygulamıyor: code.google.com/p/v8/issues/detail?id=164
Tim Down

20
"Sipariş sizin için önemliyse bir dizi kullanın": JSON kullanırken ne olur?
HM2K

11
@ HM2K, Aynı şey, spec "Bir nesne sıfır veya daha fazla ad / değer çiftinin sırasız bir koleksiyonudur." Diyor. JSON JavaScript değildir: Bir sunucunun teslim ettiğiniz sıraya uyması gerekmez (ve muhtemelen buna uymaz).
Borgar

7
Firefox, 21 sürümünden beri artık kampanya siparişine saygı duymuyor gibi görünüyor.
Doktor Davluz

3
Bu yanıt ES2015'te yanlıştır.
Benjamin Gruenbaum

54

Bunu bir yıl sonra darbelere ...

Öyle 2012 ve başlıca tarayıcılar hala farklılık gösterir:

function lineate(obj){
    var arr = [], i;
    for (i in obj) arr.push([i,obj[i]].join(':'));
    console.log(arr);
}
var obj = { a:1, b:2, c:3, "123":'xyz' };
/* log1 */  lineate(obj);
obj.a = 4;
/* log2 */  lineate(obj);
delete obj.a;
obj.a = 4;
/* log3 */  lineate(obj);

mevcut tarayıcıda gist veya test

Safari 5, Firefox 14

["a:1", "b:2", "c:3", "123:xyz"]
["a:4", "b:2", "c:3", "123:xyz"]
["b:2", "c:3", "123:xyz", "a:4"]

Chrome 21, Opera 12, Düğüm 0.6, Firefox 27

["123:xyz", "a:1", "b:2", "c:3"]
["123:xyz", "a:4", "b:2", "c:3"]
["123:xyz", "b:2", "c:3", "a:4"]

IE9

[123:xyz,a:1,b:2,c:3] 
[123:xyz,a:4,b:2,c:3] 
[123:xyz,a:4,b:2,c:3] 

16
burada sorun ne? Tam olarak belirtildiği gibi, anahtar / val çiftlerinin sırasız bir listesidir.
nickf

5
nickf: uygulamalar, spesifikasyonun söylediklerini yapmaları bakımından haklı. Herkes javascript spec olduğunu kabul ediyorum .. iyi, "yanlış" kelimesini kullanmak istemiyorum, "son derece aptal ve sinir bozucu" hakkında nasıl? : P
kutulu

10
@boxed: Nesneleri karma harita (tablo / ne olursa olsun) olarak düşünün. Çoğu dilde (Java, Python, vb.) Bu tür veri yapıları sıralanmaz. Dolayısıyla, JavaScript'te de aynı durumun olması şaşırtıcı değildir ve kesinlikle belirtimi yanlış veya aptal yapmaz.
Felix Kling

9
Dürüst olmak gerekirse bu cevabın amacını göremiyorum (üzgünüm). Özelliklerin yinelendiği sıra bir uygulama ayrıntısıdır ve tarayıcılar farklı JavaScript motorları kullanır, bu nedenle siparişin farklı olması beklenir. Bu değişmeyecek.
Felix Kling

2
En son teknoloji ürünü bir uygulamada, gerçek bir dizi tarafından desteklendiği için sayısal değer sırasıyla tamsayı özellikleri alırsınız ve gizli sınıflar / şekiller formülasyonu nedeniyle adlandırılmış özellikler ekleme sırasında alınır. Değişebilen, önce tamsayı özelliklerini mi yoksa ilk olarak adlandırılmış özellikleri mi listelediğidir. Eklenmesi deleteV8 en azından, anında nesne karma tablo tarafından yedeklenmiş neden olur çünkü ilginçtir. Ancak, V8'deki karma tablo ekleme sırasına göre depolanır. Burada en ilginç sonuç IE, bunu çıkarmak için ne tür bir çirkinlik yaptığını merak ediyorum ...
Esailija

28

Gönderen ECMAScript Dil Şartname , (bölüm 12.6.4 for .. indöngü):

Özelliklerin numaralandırılması mekaniği uygulamaya bağlıdır. Numaralandırma sırası nesne tarafından tanımlanır.

Ve bölüm 4.3.3 ("Nesne" tanımı):

Her biri ilkel bir değer, nesne veya işlev içeren sıralanmamış bir özellik koleksiyonudur. Bir nesnenin özelliğinde saklanan işleve yöntem denir.

Bu, JavaScript uygulamaları arasında tutarlı bir sırayla numaralandırılan özelliklere güvenemeyeceğiniz anlamına gelir. (Bir dilin uygulamaya özgü ayrıntılarına güvenmek yine de kötü bir stil olacaktır.)

Siparişinizin tanımlanmasını istiyorsanız, nesneyle onunla erişmeden önce sıraladığınız bir dizi anahtar gibi, onu tanımlayan bir şey uygulamanız gerekir.


10

/ İn için numaralandırılmış bir nesnenin öğeleri DontEnum bayrağı ayarlanmamış özelliklerdir. ECMAScript, yani Javascript standardı açıkça "Bir Nesne, özelliksiz bir özellik koleksiyonu" diyor (bkz. Http://www.mozilla.org/js/language/E262-3.pdf bölüm 8.6).

Tüm Javascript uygulamalarının bildirim düzeninde sıralanacağını varsaymak standartlara uygun (yani güvenli) olmayacaktır.


2
bu yüzden soruyu sormak yerine soruyor: p
Jamie Pate

5

Yineleme sırası, özelliklerin silinmesi ile de karıştırılır, ancak bu durumda yalnızca IE ile karıştırılır.

var obj = {};
obj.a = 'a';
obj.b = 'b';
obj.c = 'c';

// IE allows the value to be deleted...
delete obj.b;

// ...but remembers the old position if it is added back later
obj.b = 'bb';
for (var p in obj) {
    alert(obj[p]); // in IE, will be a, bb, then c;
                   // not a, c, then bb as for FF/Chrome/Opera/Safari
}

Http://code.google.com/p/v8/issues/detail?id=164 adresindeki tartışma herhangi bir gösterge ise , yineleme sırasını düzeltmek için spesifikasyonu değiştirme arzusu geliştiriciler arasında oldukça popüler bir arzu gibi görünüyor .


3

IE6'da sipariş garanti edilmez.


2

Siparişe güvenilemez. Hem Opera hem de Chrome sıralanmamış özelliklerin listesini döndürür.

<script type="text/javascript">
var username = {"14719":"A","648":"B","15185":"C"};

for (var i in username) {
  window.alert(i + ' => ' + username[i]);
}
</script>

Yukarıdaki kod Opera'da B, A, C ve Chrome'da C, A, B'yi gösterir.


1

Bu, soruyu kendi başına cevaplamaz, ancak temel soruna bir çözüm sunar.

Korunmak için güvenemeyeceğinizi varsayarsak, neden anahtar ve değer içeren bir nesne dizisini özellikler olarak kullanmıyorsunuz?

var myArray = [
    {
        'key'   : 'key1'
        'value' : 0
    },
    {
        'key'   : 'key2',
        'value' : 1
    } // ...
];

Şimdi, anahtarların benzersiz olmasını sağlamak sizin için önemlidir (bunun sizin için de önemli olduğunu varsayarsak.) Doğrudan adresleme değişiklikleri ve (... in ...) için dizinleri 'anahtar' olarak döndürür.

> console.log(myArray[0].key);
key1

> for (let index in myArray) {console.log(myArray[index].value);}
0
1
Kalem Bkz sırayla ele (... lütfen ...) için JDQ (tarafından @JDQ üzerine) CodePen .

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.