Menyortir properti di Javascript rusak

15

Saya perlu mengulang melalui objek JavaScript memperlakukannya sebagai array dengan kunci kustom. Saya tahu ini tidak sepenuhnya didukung, karena properti tidak memiliki urutan instrinsik, tetapi karena saya selalu memesan ulang properti, saya menemukan pendekatan ini sederhana dan dapat diandalkan ... sampai sekarang.

Masalah terjadi ketika tombol adalah angka, atau string yang dapat dicor sebagai angka.

Ketika saya menjalankan kode ini:

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

outputnya adalah:

4294966111
4294966222
4294966333
---
4294968222
4294968333
4294968111

Yang berarti:

  • (test1) jika kunci di bawah 2 ^ 32 (4.294.967.296), mereka secara otomatis disusun ulang, yang terkecil terlebih dahulu
  • (test2) jika kunci di atas 2 ^ 32, mereka TIDAK disusun ulang.

Pertanyaannya adalah: mengapa ini terjadi?

Karena semua browser yang saya uji (Google Chrome 79.0, Mozilla Firefox 71.0, Microsoft Edge 44.18362, Internet Explorer 11.535) setuju dengan output ini, harus ada beberapa spesifikasi resmi.

Memperbarui

Saya menguji banyak angka sebelum menemukan itu adalah masalah ambang batas. Saya menemukan aneh bahwa urutan 2,3,1 berperilaku berbeda dari tiga cap waktu yang dipesan dengan cara yang sama.

Kar.ma
sumber
Dugaan saya adalah bagaimana kode hash dihitung, tetapi itu bukan jawaban nyata untuk pertanyaan Anda.
Mario Vernari
1
Saya tidak berpikir itu rusak dalam arti kata sehari-hari, mereka tidak menjamin bahwa nilai-nilai akan diulang berdasarkan pesanan karena berjalan secara sewenang-wenang karena Anda dapat memeriksa developer.mozilla.org/en-US/docs/Web / JavaScript / Referensi / ... "Catatan: untuk ... di tidak boleh digunakan untuk beralih di atas Array di mana urutan indeks penting." Mereka hanya menjamin iterasi atas setiap elemen dalam koleksi. Sesuatu seperti forEach memang memperhitungkan pesanan dengan melintasi item dalam urutan naik ecma-international.org/ecma-262/5.1/#sec-15.4.4.18
Mr.Toxy
Sebagai catatan, Anda dapat melihat masalah secara langsung dengan masuk test1dan test2. Saya pikir "masalah" adalah dari caching kunci dalam implementasi V8 dari spec.
Seblor
Lebih dari itu di bawah 2 ^ 32 nama properti Anda secara kebetulan dipesan mirip dengan referensi properti internal. Anda dapat dan tidak boleh bergantung pada urutan properti objek karena menurut definisi mereka tidak diurutkan dan dapat berisi properti yang melekat objek. Selalu melemparkan / memetakan objek Anda ke dalam array, mengurutkan array, lalu memutarnya jika urutan itu penting.
user3154108
1
@ Mr.Toxy Itu karena sifat-sifat itu 4294968333dan 4294968111lebih besar dari 2 ** 32(yang 4294967296). Jadi, mereka bukan indeks array, jadi mereka diiterasi dalam urutan pembuatan properti, bukan dalam urutan numerik naik - yang persis apa yang mereka lakukan di biola, seperti yang diharapkan. (lihat jawaban saya)
Performa Tertentu

Jawaban:

4

Ini diharapkan. Per spesifikasi , metode yang mengulangi properti OrdinaryOwnPropertyKeys,, tidak:

  1. Untuk setiap kunci properti P sendiri dari O yang merupakan indeks array , dalam urutan indeks numerik naik, lakukan

    Sebuah. Tambahkan P sebagai elemen kunci terakhir.

  2. Untuk setiap kunci properti P sendiri dari O yang merupakan String tetapi bukan indeks array, dalam urutan kronologis penciptaan properti, lakukan

    Sebuah. Tambahkan P sebagai elemen kunci terakhir.

Urutan numerik naik hanya berlaku untuk properti yang merupakan indeks array.

Jadi, apa itu "indeks array"? Lihat itu ::

Indeks integer adalah kunci properti bernilai String yang merupakan String numerik kanonik (lihat 7.1.21) dan yang nilai numeriknya adalah +0 atau bilangan bulat positif ≤ 2 ^ 53 - 1. Indeks array adalah indeks integer yang numeriknya nilai i berada dalam kisaran +0 ≤ i <2 ^ 32 - 1.

Jadi, sifat numerik yang lebih besar dari 2 ^ 32 bukan indeks array, dan karena itu diurutkan dalam urutan pembuatan properti. Namun, sifat numerik yang kurang dari 2^32 yang indicies array, dan iterasi lebih dalam urutan menaik numerik.

Jadi, misalnya:

1: Array index, akan diulang lebih dari angka

10: Array index, akan diulang lebih dari angka

4294968111: Lebih besar dari 2 ** 32, akan diulang setelah indeks array selesai, dalam urutan pembuatan properti

9999999999999: Lebih besar dari 2 ** 32, akan diulang setelah indeks array selesai, dalam urutan pembuatan properti

Juga, perlu diingat bahwa, bertentangan dengan kepercayaan populer, agar iterasi properti yang dijamin oleh spesifikasi juga, berkat untuk-in iterasi usulan yang stadium 4.

Performa Tertentu
sumber
2

Ini ada hubungannya dengan cara mereka kunci suatu objek dilalui.

Menurut spesifikasi ES6 seharusnya:

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

Itu berarti jika nilai kunci tetap sama jika dikonversi ke angka 53 bit yang tidak ditandatangani dan kembali diperlakukan sebagai indeks integer yang akan diurutkan dalam urutan numerik.

Jika gagal ini diperlakukan sebagai kunci string, yang disusun sesuai dengan cara mereka ditambahkan ke objek.

Tangkapan di sini adalah bahwa semua browser utama belum mengikuti spesifikasi ini dan menggunakan indeks array sebagai gantinya terbatas pada angka positif hingga 2 ^ 32-1. Jadi apa pun di atas batas itu sebenarnya adalah kunci string.

mengaburkan
sumber