Bir şeyin tekrarlanabilir olup olmadığını kontrol etmek


105

MDN belgelerinde: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of

for...ofYapı yineleme "iterable" nesneler edebilmek için tarif edilmektedir. Ancak bir nesnenin yinelenebilir olup olmadığına karar vermenin iyi bir yolu var mı?

Diziler, yineleyiciler ve jeneratörler için ortak özellikler bulmaya çalıştım, ancak bunu yapamadım.

for ... ofBir deneme bloğu yapmanın ve tür hatalarını kontrol etmenin yanı sıra, bunu yapmanın temiz bir yolu var mı?


Elbette, yazar olarak nesnenizin yinelenebilir olup olmadığını biliyorsunuz?
andrewb

6
Nesne argüman olarak aktarılıyor, emin değilim.
simonzack

1
Neden argümanın typeof'unu test etmiyorsunuz?
James Bruckner

2
@ andrew-buchan, James Bruckner: Türleri kontrol etmek işe yarayabilir, ancak MDN belgelerini okursanız, "dizi benzeri" yazdığını fark edeceksiniz. Bunun tam olarak ne anlama geldiğini bilmiyorum, bu yüzden soru.
simonzack

1
wiki.ecmascript.org/doku.php?id=harmony:iterators , " Bir nesnenin bir iterator()yöntemi varsa yinelenebilir . " Yine de, bu bir taslak olduğu için, yalnızca bir kontrol uygulamaya bağlı olabilir. Hangi ortamı kullanıyorsunuz?
Bergi

Yanıtlar:


144

Yinelenebilirliği kontrol etmenin doğru yolu aşağıdaki gibidir:

function isIterable(obj) {
  // checks for null and undefined
  if (obj == null) {
    return false;
  }
  return typeof obj[Symbol.iterator] === 'function';
}

Bu neden işe yarar (derinlemesine yinelenebilir protokol): https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols

Hakkında konuştuğumuza göre, sanırım ES6 zihniyetindeyiz.

Ayrıca, dizeler karakterlerinin üzerinde yinelendiğinden, bu işlevin trueeğer objbir dizge olduğunu döndürdüğüne şaşırmayın .


15
veya Symbol.iterator in Object(obj),.

14
'İn' operatörü kullanmanın (en az) bir istisnası vardır: string. String yinelenebilir (for..of açısından) ancak üzerinde 'in' kullanamazsınız. Bunun için değilse, kesinlikle daha güzel görünüyor 'in' kullanmayı tercih ederim.
Tomas Kulich

olması gerekmiyor return typeof obj[Symbol.iterator] === 'function'mu? "Yinelenebilir olması için, bir nesnenin @@ yineleyici yöntemini uygulaması gerekir" - yöntemi belirtir
callum

Obj [Symbol.iterator] 'ın (undefined veya) işlevinden başka bir şey olması için uygun anlambilim yoktur. Örneğin birisi String'i oraya koyarsa, bu kötü bir şeydir ve IMO, kodun mümkün olan en kısa sürede başarısız olması durumunda iyidir.
Tomas Kulich

Misiniz typeof Object(obj)[Symbol.iterator] === 'function'her durumda işe?
Craig Gidney

25

Neden bu kadar ayrıntılı?

const isIterable = object =>
  object != null && typeof object[Symbol.iterator] === 'function'

57
Readability > Clevernessher zaman geri döner true.
jfmercer

29
Haha, normalde okunamayan kodlardan şikayet eden benim, ama aslında bunun oldukça okunabilir olduğunu düşünüyorum. İngilizce bir cümle gibi: Nesne boş değilse ve sembolik yineleyici özelliği bir işlevse, yinelenebilir. Bu kadar basit değilse, ne olduğunu bilmiyorum ...
adius

4
imo, "okunabilirliğin" amacı, gerçek okuma olmadan neler olduğunu anlamaktır
Dima Parzhitsky

2
@Alexander Mills Geliştirmeniz kodu daha da kötüleştirdi. 1. gibi @jfmercer sözü Readability > Clevernessöylesine değişken kısaltarak objectiçin okimseyi yardımcı olur. 2. Boş bir dizge ''yinelenebilir ve bu nedenle geri dönmesi gerekir true.
adius

2
Belki, sen okuma gereken tek şey adıdır: isIterable.
Matthias

22

En basit çözüm aslında şudur:

function isIterable (value) {
  return Symbol.iterator in Object(value);
}

Objectnesne olmayan her şeyi bir arada sararak in, orijinal değer bir Object olmasa bile operatörün çalışmasına izin verir . nullve undefinedboş nesnelere dönüştürülür, böylece uç durum algılamaya gerek kalmaz ve dizeler yinelenebilir String nesnelerine sarılır.


1
Yanlış sembolü kullandın. Bu açıklanmıştır: Symbol.iterator.
Gil

@Gil Kesinlikle haklısın, oops! Doğrudan bir gönderiye yazmak yerine test edilmiş kodu kopyalayıp yapıştırmış olmalıyım.
Domino

Objectİle yeni bir nesnenin oluşturulması bu tür kontroller için israftır.
Ruben Verborgh

ObjectFonksiyonun tam olarak nasıl uygulandığını bildiğimi söyleyemem , ancak sadece valuehalihazırda bir nesne değilse yeni bir nesne yaratır . Söylenenin aksine, tarayıcı motorlarının kolayca optimize edebileceği bir kombinasyon inve olmasını beklerdim . Artı, benim önemsediğim son derece okunabilir. Object(...)value !== undefined && value !== null && value[Symbol.iterator] && true
Domino

9

Bir yan not olarak , yinelenebilir kavramının tanımı hakkında DİKKAT EDİN . Başka dillerden geliyorsanız, tekrarlayabileceğiniz bir şeyin, örneğin bir döngü tekrarlanabilir olmasını beklersiniz . Korkarım, yinelenebilirliğin yineleme protokolünü uygulayan bir anlamı olduğu burada durum böyle değilfor .

İşleri daha net hale getirmek için, yukarıdaki tüm örnekler falsebu nesneye geri döner {a: 1, b: 2}çünkü bu nesne yineleme protokolünü uygulamaz. Yani bir ile bunu yineleyemeyeceksiniz, for...of ANCAK yine de birfor...in .

Bu nedenle, acı verici hatalardan kaçınmak istiyorsanız, yönteminizi aşağıda gösterildiği gibi yeniden adlandırarak kodunuzu daha spesifik hale getirin:

/**
 * @param variable
 * @returns {boolean}
 */
const hasIterationProtocol = variable =>
    variable !== null && Symbol.iterator in Object(variable);

Hiç mantıklı değilsin. Neden bozulacağını düşünüyorsun undefined?
adius

@adius Sanırım cevabınızda yanlış bir şekilde yaptığınızı varsaymıştım object !== nullama yapıyorsunuz object != nullöyle yapıyorsunuz undefined, bu belirli durumda kopmuyor . Cevabımı buna göre güncelledim.
Francesco Casula

Tamam anladım. Btw: Kodunuz yanlış. hasIterationProtocol('')geri dönmeli true! Kodunuzu kaldırıp cevabınıza gerçek değer / yeni bir şey katan tek şey olan yinelenebilir açıklama bölümünü bırakmaya ne dersiniz?
adius

1
trueEski cevabın bir kısmını kaldırarak geri dönüyor , her iki işlevi de birleştirdim ve katı karşılaştırmayı unuttum. Şimdi iyi çalışan orijinal cevabı geri koydum.
Francesco Casula

1
Kullanmayı hiç düşünmemiştim Object(...), güzel yakala. Ancak bu durumda sıfır kontrolüne gerek yoktur.
Domino

3

İçin zaman uyumsuz Yineleyicilerin yerine 'Symbol.iterator' arasında 'Symbol.asyncIterator' için kontrol etmelidir:

async function* doSomething(i) {
    yield 1;
    yield 2;
}

let obj = doSomething();

console.log(typeof obj[Symbol.iterator] === 'function');      // false
console.log(typeof obj[Symbol.asyncIterator] === 'function'); // true

2

Bugünlerde, daha önce de belirtildiği gibi obj, yinelenebilir olup olmadığını test etmek için

obj != null && typeof obj[Symbol.iterator] === 'function' 

Tarihsel cevap (artık geçerli değil)

for..ofYapı ECMAscript 6th edition Dil Şartname Taslağı parçasıdır. Böylece son versiyondan önce değişebilir.

Bu taslakta, yinelenebilir nesnelerin işlevi olmalıdıriterator bir özellik olarak .

Bir nesnenin şu şekilde yinelenebilir olup olmadığını kontrol edebilirsiniz:

function isIterable(obj){
   if(obj === undefined || obj === null){
      return false;
   }
   return obj.iterator !== undefined;
}

7
Yineleyici özelliği geçici bir firefox özelliğiydi. ES6 uyumlu değil. bakınız: developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Amir Arad

1

Bir değişkenin bir nesne ( {key: value}) veya bir dizi ( [value, value]) olup olmadığını kontrol etmek istiyorsanız, bunu yapabilirsiniz:

const isArray = function (a) {
    return Array.isArray(a);
};

const isObject = function (o) {
    return o === Object(o) && !isArray(o) && typeof o !== 'function';
};

function isIterable(variable) {
    return isArray(variable) || isObject(variable);
}
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.