Bunu bir deneyeceğim. ECMA ile bağlantım olmadığına ve karar verme süreçlerine dair hiçbir görünürlüğüm olmadığına dikkat edin, bu nedenle neden hiçbir şey yapıp yapmadıklarını kesin olarak söyleyemem . Ancak, varsayımlarımı ifade edeceğim ve en iyi atışımı yapacağım.
1. Neden for...of
ilk olarak bir yapı eklemelisiniz ?
JavaScript zaten for...in
bir nesnenin özelliklerini yinelemek için kullanılabilecek bir yapı içerir . Ancak, bir nesnedeki tüm özellikleri numaralandırdığı ve yalnızca basit durumlarda tahmin edilebilir şekilde çalışma eğiliminde olduğu için bu gerçekten bir forEach döngüsü değildir .
Daha karmaşık durumlarda (diziler dahil, kullanımının cesaretinin kırıldığı veyafor...in
bir diziyle doğru bir şekilde kullanılması için gereken güvenlik önlemleri tarafından tamamen karıştırıldığı durumlarda) bozulur . hasOwnProperty
(Diğer şeylerin yanı sıra) kullanarak bunun üstesinden gelebilirsiniz , ancak bu biraz hantal ve uygunsuz.
Dolayısıyla benim varsayımım, yapının for...of
yapıyla ilişkili eksiklikleri gidermek for...in
ve şeyleri yinelerken daha fazla fayda ve esneklik sağlamak için ekleniyor olmasıdır . İnsanlar genellikle herhangi bir koleksiyona uygulanabilen ve olası herhangi bir bağlamda mantıklı sonuçlar üreten for...in
bir forEach
döngü gibi davranma eğilimindedir , ancak olan bu değildir. for...of
Döngü giderdiği.
Ayrıca, mevcut ES5 kodunun ES6 altında çalışmasının ve ES5 altında olduğu gibi aynı sonucu üretmesinin önemli olduğunu varsayıyorum, bu nedenle, örneğin yapının davranışında kırma değişiklikleri yapılamaz for...in
.
2. Nasıl for...of
çalışır?
Referans belgeleri bu bölümü için yararlıdır. Özellikle, özelliği iterable
tanımlıyorsa bir nesne dikkate alınır Symbol.iterator
.
Özellik tanımı, koleksiyondaki öğeleri tek tek döndüren ve getirilecek daha fazla öğe olup olmadığını gösteren bir bayrak ayarlayan bir işlev olmalıdır. Bazı nesne türleri için önceden tanımlanmış uygulamalar sağlanır for...of
ve yineleyici işlevi için basit temsilcilerin kullanılması nispeten açıktır .
Bu yaklaşım, kendi yineleyicilerinizi sağlamayı çok kolaylaştırdığı için kullanışlıdır. Yaklaşımın, daha önce hiç bulunmayan bir mülkü tanımlamaya dayanması nedeniyle pratik sorunlar ortaya koymuş olabileceğini söyleyebilirim, ancak bunun böyle olmadığını söyleyebilirim, çünkü siz kasıtlı olarak aramaya gitmedikçe, yeni mülk esasen göz ardı edilir. for...in
döngülerde anahtar olarak bulunmaz , vb.). Yani durum bu değil.
Pratik olmayan konular bir yana, tüm nesneleri yeni bir önceden tanımlanmış özellik ile başlatmak veya örtük olarak "her nesne bir koleksiyondur" demek kavramsal olarak tartışmalı olarak değerlendirilebilirdi.
3. Nesneler neden varsayılan olarak iterable
kullanmıyor for...of
?
Benim tahminim bu bir kombinasyonu olmasıdır:
- Tüm nesneleri
iterable
varsayılan olarak yapmak, daha önce hiç bulunmayan bir özelliği eklediğinden veya bir nesnenin (zorunlu olarak) bir koleksiyon olmadığı için kabul edilemez olarak değerlendirilebilir. Felix'in belirttiği gibi, "bir işlev veya normal ifade nesnesi üzerinde yineleme yapmak ne anlama gelir"?
- Basit nesneler kullanılarak zaten yinelenebilir
for...in
ve yerleşik bir yineleyici uygulamasının mevcut for...in
davranıştan farklı / daha iyi ne yapabileceği açık değildir . Dolayısıyla, # 1 yanlış olsa ve özelliği eklemek kabul edilebilir olsa bile, yararlı olarak görülmemiş olabilir .
- Nesnelerini yapmak isteyen kullanıcılar
iterable
, Symbol.iterator
özelliği tanımlayarak bunu kolayca yapabilirler .
- ES6 Spec ayrıca sağlayan Harita türünü olduğu
iterable
varsayılan ve bir düz nesneyi kullanımına kıyasla bazı diğer küçük avantajları vardır Map
.
Referans belgelerde # 3 için verilen bir örnek bile var:
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
for (var value of myIterable) {
console.log(value);
}
Nesnelerin kolayca yapılabileceği iterable
, kullanılarak yinelenebilecekleri for...in
ve varsayılan bir nesne yineleyicinin ne yapması gerektiği konusunda muhtemelen net bir fikir birliği olmadığı göz önüne alındığında (eğer yaptığı şey, yapandan bir şekilde farklı olacaksa for...in
), makul görünmektedir. nesnelerin iterable
varsayılan olarak yapılmaması yeterlidir .
Örnek kodunuzun aşağıdakiler kullanılarak yeniden yazılabileceğini unutmayın 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]);
}
}
... veya iterable
aşağıdaki gibi bir şey yaparak nesnenizi istediğiniz şekilde de oluşturabilirsiniz (veya bunun yerine atayarak tüm nesneleri oluşturabilirsiniz ):iterable
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
};
};
Bununla burada oynayabilirsiniz (Chrome'da, kiralanabilir): http://jsfiddle.net/rncr3ppz/5/
Düzenle
Ve güncellenmiş sorunuza yanıt olarak, evet, ES6'daki yayılma operatörünüiterable
kullanarak bir diziye dönüştürmek mümkündür .
Ancak, bu henüz Chrome'da çalışmıyor gibi görünüyor veya en azından jsFiddle'ımda çalışmasını sağlayamıyorum. Teorik olarak şu kadar basit olmalıdır:
var array = [...myIterable];
Symbol.iterator
Özelliği olan her şey yinelenebilir. Yani sadece o mülkü uygulamanız gerekir. Bir olası nesneler iterable bu ima edeceğini olabilir değil neden için açıklama her şeyi her şeyi (tabii ki ilkel hariç) bir nesne olduğundan, iterable oldu. Bununla birlikte, bir işlev veya normal ifade nesnesi üzerinde yineleme yapmak ne anlama gelir?