Iterable objeleri dizilerin genelleÅtirilmiÅ halidir. Bu her objenin for..of döngüsünde kullanılmasına olanak verir.
Diziler zaten tekrarlanabilirdir. Fakat sadece diziler deÄil, karakter dizileri de tekrarlanabilir.
Sıralı eriÅim JavaScript çekirdeÄince oldukça fazla kullanılır. Varolan operatörler ve metodların birçoÄu buna bel baÄlar.
Symbol.iterator
Sıralı eriÅimin matıÄını en iyi Åekilde kendimiz bir tane yaparak anlayabiliriz.
ÃrneÄin bir objeniz var, dizi deÄil, fakat for..of için uygun duruyor.
ÃrneÄin aralik objesi iki sayı arasını tanımlasın.
let aralik = {
baslangic: 1,
bitis: 5
};
// for..of 'un
// for(let sayi of aralik) ... sayi=1,2,3,4,5 Åeklinde çalıÅmasını istiyoruz.
aralikâe sıralı eriÅim yapabilmek ( for..of ile çalıÅtırabilmek ) için Symbol.iterator isminde bir metoda sahip olması gerekmektedir. ( özel bir sembol)
for..ofbaÅladıÄında, bu metod çaÄırılır ve eÄer bulunamazsa hata verir.- metod iterator döndürmelidir. ( Sıralı eriÅim objesi) bu obje
nextmetoduna sahip olmalıdır. for..ofbir sonraki deÄeri istediÄindenext()metodu çaÄırılacaktır.next()metodu sonrasında{done:Boolean, value:any},done = truedönerse sıralı eriÅimin bittiÄi anlaÅılır. Aksi haldevalueyeni deÄer olacaktır.
AÅaÄıda aralik fonksiyonunun uygulamasını görebilirsiniz:
let aralik = {
baslangic: 1,
bitis: 5
};
// for..of çaÄırıldıÄında doÄrudan aÅaÄıdaki metod çaÄırılır.
aralik[Symbol.iterator] = function() {
// 2. geriye sıralı eriÅim elemanı döndürür:
return {
current: this.baslangic,
last: this.bitis,
// 3. next() is called on each iteration by the for..of loop
// for..of her defasında next() metodunu çaÄırır.
next() {
// 4. bu metod geriye Åu Åekilde obje döndürmeli {done:.., value :...}
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
};
// çalıÅması!
for (let num of aralik) {
alert(num); // 1, then 2, 3, 4, 5
}
Bu kod için bir tane çok önemli problem mevcuttur:
aralikfonksiyonunun kendisinext()metoduna sahip deÄildir.- Bunun yerine, diÄer bir obje,
aralik[Symbol.iterator]()ile yaratılmaktadır ve bu sıralı eriÅimi saÄlar.
Bundan dolayı sıralı eriÅim objesi aslında sıralı eriÅilecek objeden farklıdır.
Teknik olarak aralik içerisine bu metodu yazarak kodu daha sade yapabiliriz.
AÅaÄıdaki gibi:
let aralik = {
baslangic: 1,
bitis: 5,
[Symbol.iterator]() {
this.current = this.baslangic;
return this;
},
next() {
if (this.current <= this.bitis) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
for (let num of aralik) {
alert(num); // 1, then 2, 3, 4, 5
}
Åu anda aralik[Symbol.iterator]() gerçek aralik objesini gönderir: gerekli olan next() metodunu dönderir ve o anki tekrar durumunu this.current ile hatırlar. Bazen bu da iyidir. Bunun kötü tarafı ise iki tane for..of olamamasıdır. Ãünkü bu döngüler objelerin üzerinden aynı anda geçerler: tek bir tane obje olduÄundan dolayı döngünün durumunu paylaÅırlar bu da karıÅıklıÄa neden olur.
Sonsuz sıralı döngüler de yapılabilirdir. ÃrneÄin aralik range.to = Infinity olursa sonsuza kadar gider. Bunun yanında rasgele sayılar üreterek bu sırayı öldürmeyen bir döngü yapmak da mümkündür.
next için bir limitasyon yoktur, istendiÄi kadar çok deÄer gönderebilir.
Tabiki böyle bir durumda for..of döngüsü sonsuza kadar devam eder. Bunun yanında bu döngüyü break ile kırmakta mümkündür.
Karakter dizilerine sıralı eriÅim
Diziler ve karakter dizileri(string) en fazla kullanılan sıralı eriÅime sahip tiplerdir.
Karakter için for..of karakterleri üzerinden geçer:
for(let char of "test") {
alert( char ); // t, sonra e, sonra s, sonra t
}
Vekil çiflerin yerine geçerek de çalıÅabilir.
let str = 'ð³ð';
for(let char of str) {
alert(char); // ð³, sonra ð
}
Sıralı eriÅim elemanlarını dıÅardan çaÄırma
Normalde, sıralı eriÅim elemanları dıÅardan kod çaÄırmaya kapatılmıÅtır. for..of döngüsü çalıÅır ve bu da tek bilinmesi gereken olaydır.
Olayı daha derinlemesine anlayabilmek için dıÅarıdan nasıl sıralı eriÅim yaratılır buna bakalım.
Karakter dizisini aynı for..of gibi döneceÄiz fakat doÄrudan çaÄrılarla. Bu kod karakter dizisi eriÅim elemanını alır ve bunu manuel bir Åekilde yapar:
let str = "Hello";
// for (let char of str) alert(char);
// ile aynı Åekilde çalıÅır
let iterator = str[Symbol.iterator]();
while(true) {
let result = iterator.next();
if (result.done) break;
alert(result.value); //karakterlerin bir bir çıktısını verir.
}
Buna çok nadir ihtiyaç olur. Fakat bu bize for..ofâtan daha fazla kontrol yetkisi verir. ÃrneÄin bu sıralı eriÅim olayını bazen çalıÅtırıp bazen çalıÅtırma veya o ara bir Åeyler yaptırma mümkün olmaktadır.
Döngüler ve dizi-benzerleri
İki tane resmi tanım vardır. Birbirlerine çok benzeseler de aslında çok farklıdırlar. Lütfen ikisini de iyi bir Åekilde anlayın böylece karmaÅıklıktan kurtulabilirsiniz.
- Iterables
Symbol.iteratormethodunun uygulamasını yapan objelerdir. - Array-likes index ve
lengthözelliklerine sahip dizi benzeri objelerdir.
DoÄal olarak bu özellikler birleÅtirilebilir. ÃrneÄin, karakterler hem iterable(sıralı döngü elemanı, for..of kullanmaya müsaittir) hemde dizi benzeri ( sayısal indeksleri bulunur ve length özelliÄine sahiptirler.)
Fakat her iterable obje dizi benzeri olmayabilir. DiÄeri de doÄrudur yani her dizi benzeri, iterable olmayabilir.
ÃrneÄin, yukarıda bulunan aralık fonksiyonu iterableâdır. Fakat dizi benzeri deÄildir. Ãünkü indekslenmiŠözellikleri veya length özelliÄi bulunmamaktadır.
AÅaÄıda dizi benzeri olan fakat iterable olmayan obje gösterilmiÅtir.
let diziBenzeri = { // indekslere ve uzunluÄa sahiptir => dizi-benzeri
0: "Merhaba",
1: "Dünya",
length: 2
};
// Hata Symbol.iterator bulunmamaktadır.
for(let eleman of diziBenzeri) {}
Ortak noktalaraı ikisinin de dizi olmamasıdır. Bunların push veya pop gibi metodları bulunmamaktadır. EÄer dizi ile çalıÅmak istiyorsanız bunlar yetersiz kalırlar.
Array.from
Bunları bir araya getirip dizi yapmaya yarayan Array.from metodudur. Sonrasında dizi metodları çaÄrılabilir.
ÃrneÄin:
let diziBenzeri = {
0: "Merhaba",
1: "Dünya",
length: 2
};
let arr = Array.from(diziBenzeri); // (*)
alert(arr.pop()); // Dünya (metod çalıÅmakta)
(*) satırında bulunan Array.from objeyi alır. Objenin sıralı eriÅim objesi mi yoksa dizi-benzeri mi olduÄunu kontrol eder ve ardından bu deÄerleri kopyalayarak yeni dizi yaratır.
Aynısı sıralı eriÅim objesi için de yapılabilir:
// AralıÄın yukarıdaki örnekten alındıÄını varsayarsanız.
let arr = Array.from(aralik);
alert(arr); // 1,2,3,4,5 (dizinin toString metodu çalıÅır)
Bunun yanında Array.from metodu opsiyonel olarak âmappingâ fonksiyonuna izin verir:
Array.from(obj[, mapFn, thisArg])
mapFn argümanı her elemanın diziye eklenmeden önce uygulanacaÄı fonksiyondur, ve thisArg bunun için thisi ayarlar.
ÃrneÄin:
// aralik'in yukarıdan alındıÄı varsayılırsa
// her sayının karesinin alınması.
let arr = Array.from(aralik, num => num * num);
alert(arr); // 1,4,9,16,25
burada Array.from kullanarak karakter karakter dizisi haline getirilmiÅtir.
let str = 'ð³ð';
// karakterden karakterler dizisi yapma
let chars = Array.from(str);
alert(chars[0]); // ð³
alert(chars[1]); // ð
alert(chars.length); // 2
str.splitâe benzemeksizin, karakter dizisinin tekrar edilebilirliÄine göre for..of gibi vekil çiftler ile doÄru bir Åekilde çalıÅır.
Teknik olarak burada da aynısı yapılmaktadır:
let str = 'ð³ð';
let chars = []; // Array.from içinde aynı Åeyi yapmaktadır.
for(let char of str) {
chars.push(char);
}
alert(chars);
â¦fakat daha kısa.
Hatta vekil-farkında slice yapılabilir.
function slice(str, start, end) {
return Array.from(str).slice(start, end).join('');
}
let str = 'ð³ðð©·¶';
alert( slice(str, 1, 3) ); // ðð©·¶
// Varolan metodlar vekil çiftleri desteklemez.
alert( str.slice(1, 3) ); // çöp
Ãzet
Objeler for..of ile kullanılırsa sıralı eriÅim objesi adını alır.
- Teknik olarak, sıralı eriÅim objelerinin
Symbol.iteratormetodunu uygulamıŠolması gerekir.obj[Symbol.iterator]'ün sonucunda bu objeye sıralı eriÅim objesi denir vefor..ofiçerisinde tekrarlanabilir.- Bir sıralı eriÅim objesi
next()metoduna kesinlikle sahip olmalıdır. Bu metod{ done: Boolean, value:any}döndürmelidir. Buradadone:trueolur ise bu döngü bitti anlamına gelir. DiÄer türlüvaluebir sonraki deÄerdir.
Symbol.iteratormetodufor..oftarafından otomatik olarak çaÄrılmaktadır. Elbette doÄrudan da çaÄırılabilir.- Var olan sıralı eriÅilebilir objeler, yani karakterler ve diziler de
Symbol.iteratormetodunu yapmıÅlardır. - Karakter döngüsü vekil ikilileri anlayabilir.
İndekslenmiŠözelliklere ve length özelliÄine sahip objelere dizi-benzeri denir. Böyle objeler baÅka özellik ve metodlara da sahip olabilir. Fakat dizilerin sahip olduÄu metodlardan yoksundurlar.
EÄer Åartnameye bakılacak olursa â Varolan çoÄu metodun iterables veya dizi-benzeri ile çalıÅabileceÄi vurgulanmıÅtır. Gerçek diziler daha soyut kalmaktadır bundan dolayı pek bahsedilmez.
Array.from(obj[, mapFn, thisArg]) metodu iterable veya dizi-benzeriâinden gerçek Array üretirler, sonrasında bunu herhangi bir dizi metoduyla kullanılabilir. mapFn ve thisArg gibi isteÄe baÄlı metodlar dizinin her bir elemanın istenilen fonksiyona uygular.
Yorumlar
<code>kullanınız, birkaç satır eklemek için ise<pre>kullanın. EÄer 10 satırdan fazla kod ekleyecekseniz plnkr kullanabilirsiniz)