Saya akan mencoba ini. Perhatikan bahwa saya tidak berafiliasi dengan ECMA dan tidak dapat melihat proses pengambilan keputusan mereka, jadi saya tidak dapat secara pasti mengatakan mengapa mereka telah atau belum melakukan apa pun. Namun, saya akan menyatakan asumsi saya dan melakukan yang terbaik.
1. Mengapa menambahkan for...of
konstruksi di tempat pertama?
JavaScript sudah menyertakan for...in
konstruksi yang dapat digunakan untuk mengulang properti suatu objek. Namun, ini sebenarnya bukan perulangan forEach , karena ia menyebutkan semua properti pada sebuah objek dan cenderung hanya bekerja dengan diprediksi dalam kasus sederhana.
Ini rusak dalam kasus yang lebih kompleks (termasuk dengan larik, di mana penggunaannya cenderung tidak disarankan atau sepenuhnya dikaburkan oleh pengamanan yang diperlukan untuk digunakan for...in
dengan larik dengan benar ). Anda dapat mengatasinya dengan menggunakan hasOwnProperty
(antara lain), tetapi itu agak kikuk dan tidak elegan.
Jadi oleh karena itu asumsi saya adalah bahwa for...of
konstruksi sedang ditambahkan untuk mengatasi kekurangan yang terkait dengan for...in
konstruksi tersebut, dan memberikan utilitas dan fleksibilitas yang lebih besar saat melakukan iterasi. Orang cenderung memperlakukan for...in
sebagai forEach
loop yang secara umum dapat diterapkan pada koleksi apa pun dan menghasilkan hasil yang waras dalam konteks yang memungkinkan, tetapi bukan itu yang terjadi. The for...of
Loop perbaikan itu.
Saya juga berasumsi bahwa penting untuk kode ES5 yang ada untuk berjalan di bawah ES6 dan menghasilkan hasil yang sama seperti di bawah ES5, jadi perubahan yang melanggar tidak dapat dilakukan, misalnya, pada perilaku for...in
konstruksi.
2. Bagaimana cara for...of
kerjanya?
The dokumentasi referensi berguna untuk bagian ini. Secara spesifik, sebuah objek dipertimbangkan iterable
jika ia mendefinisikan Symbol.iterator
properti.
Definisi properti harus berupa fungsi yang mengembalikan item dalam koleksi, satu, oleh, satu, dan menyetel bendera yang menunjukkan apakah ada lebih banyak item untuk diambil atau tidak. Implementasi yang telah ditentukan disediakan untuk beberapa tipe objek , dan cukup jelas bahwa for...of
hanya menggunakan delegasi ke fungsi iterator.
Pendekatan ini berguna, karena membuatnya sangat mudah untuk menyediakan iterator Anda sendiri. Saya dapat mengatakan bahwa pendekatan tersebut dapat menyajikan masalah praktis karena ketergantungannya pada pendefinisian properti yang sebelumnya tidak ada, kecuali dari apa yang dapat saya katakan bukan itu masalahnya karena properti baru pada dasarnya diabaikan kecuali Anda sengaja mencarinya (mis. itu tidak akan muncul dalam for...in
loop sebagai kunci, dll.). Jadi bukan itu masalahnya.
Terlepas dari non-masalah praktis, mungkin telah dianggap kontroversial secara konseptual untuk memulai semua objek dengan properti baru yang telah ditentukan sebelumnya, atau secara implisit mengatakan bahwa "setiap objek adalah koleksi".
3. Mengapa objek tidak iterable
digunakan for...of
secara default?
Dugaan saya adalah bahwa ini adalah kombinasi dari:
- Membuat semua objek
iterable
secara default mungkin dianggap tidak dapat diterima karena menambahkan properti yang sebelumnya tidak ada, atau karena objek tidak (harus) merupakan koleksi. Seperti yang Felix catat, "apa artinya mengulang fungsi atau objek ekspresi reguler"?
- Objek sederhana sudah dapat diulang menggunakan
for...in
, dan tidak jelas apa implementasi iterator built-in bisa dilakukan secara berbeda / lebih baik dari for...in
perilaku yang ada . Jadi, meskipun # 1 salah dan menambahkan properti dapat diterima, mungkin tidak terlihat berguna .
- Pengguna yang ingin membuat objeknya
iterable
dapat dengan mudah melakukannya, dengan mendefinisikan Symbol.iterator
properti.
- Spesifikasi ES6 juga menyediakan tipe Peta , yang secara
iterable
default dan memiliki beberapa keuntungan kecil lainnya dibandingkan menggunakan objek biasa sebagai Map
.
Bahkan ada contoh yang diberikan untuk # 3 dalam dokumentasi referensi:
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
for (var value of myIterable) {
console.log(value);
}
Mengingat bahwa objek dapat dengan mudah dibuat iterable
, bahwa mereka sudah dapat diiterasi menggunakan for...in
, dan bahwa ada kemungkinan tidak ada kesepakatan yang jelas tentang apa yang harus dilakukan oleh iterator objek default (jika apa yang dilakukannya dimaksudkan untuk entah bagaimana berbeda dari apa yang for...in
dilakukannya), tampaknya masuk akal cukup sehingga objek tidak dibuat iterable
secara default.
Perhatikan bahwa kode contoh Anda dapat ditulis ulang menggunakan for...in
:
for (let levelOneKey in object) {
console.log(levelOneKey);
console.log(object[levelOneKey]);
var levelTwoObj = object[levelOneKey];
for (let levelTwoKey in levelTwoObj ) {
console.log(levelTwoKey);
console.log(levelTwoObj[levelTwoKey]);
}
}
... atau Anda juga dapat membuat objek iterable
sesuai keinginan dengan melakukan sesuatu seperti berikut (atau Anda dapat membuat semua objek iterable
dengan menetapkannya Object.prototype[Symbol.iterator]
):
obj = {
a: '1',
b: { something: 'else' },
c: 4,
d: { nested: { nestedAgain: true }}
};
obj[Symbol.iterator] = function() {
var keys = [];
var ref = this;
for (var key in this) {
keys.push(key);
}
return {
next: function() {
if (this._keys && this._obj && this._index < this._keys.length) {
var key = this._keys[this._index];
this._index++;
return { key: key, value: this._obj[key], done: false };
} else {
return { done: true };
}
},
_index: 0,
_keys: keys,
_obj: ref
};
};
Anda dapat memainkannya di sini (di Chrome, sewa): http://jsfiddle.net/rncr3ppz/5/
Sunting
Dan sebagai tanggapan atas pertanyaan Anda yang telah diperbarui, ya, dimungkinkan untuk mengonversi sebuah iterable
menjadi larik, menggunakan operator sebaran di ES6.
Namun, ini sepertinya belum berfungsi di Chrome, atau setidaknya saya tidak bisa membuatnya berfungsi di jsFiddle saya. Secara teori, ini harus sesederhana:
var array = [...myIterable];
Symbol.iterator
properti bersifat iterable. Jadi, Anda hanya perlu menerapkan properti itu. Satu penjelasan yang mungkin mengapa objek tidak dapat diulang bisa jadi bahwa ini menyiratkan semuanya dapat diulang, karena semuanya adalah objek (kecuali primitif tentu saja). Namun, apa artinya mengulang fungsi atau objek ekspresi reguler?