反復可能かどうかの確認


104

MDNドキュメント:https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of

for...ofコンストラクトは「反復可能な」オブジェクトを反復処理することができるように記述されています。しかし、オブジェクトが反復可能かどうかを判断する良い方法はありますか?

配列、イテレータ、ジェネレータの一般的なプロパティを見つけようとしましたが、見つけることができませんでした。

別に行うためのfor ... oftryブロックにし、型エラーをチェックし、これを行うクリーンな方法は何ですか?


確かに、作成者として、オブジェクトが反復可能かどうか知っていますか?
アンドリューブ2013

5
オブジェクトは引数として渡されますが、よくわかりません。
simonzack 2013

1
なぜ引数のtypeofをテストしないのですか?
James Bruckner

2
@ andrew-buchan、James Bruckner:型のチェックは機能するかもしれませんが、MDNドキュメントを読むと、「配列のような」と表示されていることに気づくでしょう。これが何を意味するのか、正確にはわかりません。
simonzack 2013

1
wiki.ecmascript.org/doku.php?id=harmony:iteratorsは「オブジェクトは、iterator()メソッドがあれば反復可能です」と述べています。しかし、これはドラフトなので、チェックのみが実装に依存する可能性があります。どのような環境を使用していますか?
ベルギ

回答:


142

反復可能性をチェックする適切な方法は次のとおりです。

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

これが機能する理由(反復可能なプロトコルの詳細):https : //developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols

私たちはfor..ofについて話しているので、私はES6の考え方にいると思います。

また、文字列が文字に対して反復するため、この関数が文字列のtrue場合にこの関数が返されることにも驚かないでくださいobj


14
または、Symbol.iterator in Object(obj)

14
'in'演算子の使用には(少なくとも)1つの例外があります:文字列。文字列は(for..ofに関して)反復可能ですが、 'in'を使用することはできません。そうでない場合は、「in」を使用した方が間違いなく見栄えが良くなります。
Tomas Kulich

そうじゃないのreturn typeof obj[Symbol.iterator] === 'function'?「反復可能であるためには、オブジェクトは@@ iteratorメソッドを実装する必要があります」–これはメソッドを指定します
callum

obj [Symbol.iterator]が(未定義または)関数以外のものであるための適切なセマンティクスはありません。誰かが例えばStringをそこに置いた場合、それは悪いことであり、IMOは、コードができるだけ早く失敗した場合に適しています。
Tomas Kulich 2016年

typeof Object(obj)[Symbol.iterator] === 'function'、すべての場合に動作しますか?
Craig Gidney、2016

26

なぜそんなに冗長なのですか?

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

56
Readability > Cleverness常に戻りますtrue
jfmercer 2016年

26
ははは、普段は読めないコードについて文句を言うのは私ですが、実際にはこれはかなり読みやすいと思います。英語の文のように:オブジェクトがnullではなく、シンボリックイテレータプロパティが関数である場合、それは反復可能です。それが
完全に

4
イモ、「読みやすさ」のポイントは、実際の読書なしで何が起こっているのかを理解することです
Dmitry Parzhitsky

2
@Alexander Millsあなたの改善はコードを悪化させました。1. @jfmercerが言ったReadability > Clevernessように、変数objectを短くしてo誰も役に立たないようにします。2.空の文字列''は反復可能であるため、返す必要がありtrueます。
adius

1
了解しました。使用している理由があると思いました!= null
Alexander Mills

22

最も簡単な解決策は実際にはこれです:

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

Objectオブジェクトではないものを1つにラップしin、元の値がオブジェクトではない場合でも、オペレーターが作業できるようにします。nullそして、undefinedエッジケースを検出するための必要はありませんので、空のオブジェクトに変換され、文字列は反復可能ですStringオブジェクトにラップます。


1
間違った記号を使用しました。それは:Symbol.iteratorです。
ギル

@ギルあなたは完全に正しい、おっと!投稿に直接入力する代わりに、コピーして貼り付けたテスト済みコードを用意する必要があります。
ドミノ(

での新しいオブジェクトの作成は、Objectこのタイプのチェックには無駄です。
Ruben Verborgh

Object関数がどのように実装されているかを正確に知っているvalueとは言えませんが、まだオブジェクトがない場合にのみ、新しいオブジェクトを作成します。とは異なり、の組み合わせinObject(...)ブラウザエンジンが簡単に最適化できるものになることを期待していますvalue !== undefined && value !== null && value[Symbol.iterator] && true。加えて、それは私が気にかけている非常に読みやすいです。
ドミノ

9

追記として、用心の定義について反復可能。あなたが他の言語から来ているなら、あなたはあなたが反復できる何か、例えばforループが反復可能であることを期待するでしょう。iterable反復プロトコルを実装する何かを意味する場合、ここではそうではありません。

わかりやすくするために、falseこのオブジェクト{a: 1, b: 2}は反復プロトコルを実装していないため、上記のすべての例ではこのオブジェクトが返されます。あなたがそれを反復処理することができませんので、for...of しかし、あなたはまだでできますfor...in

したがって、苦痛な間違いを避けたい場合は、次のようにメソッドの名前を変更して、コードをより具体的にします。

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

あなたは意味がありません。なぜそれが壊れると思いますundefinedか?
adius

@adius私はあなたがobject !== nullあなたの答えで間違っていたと思いましたが、あなたはそうしているobject != nullのでundefined、その特定のケースでは壊れません。私はそれに応じて私の答えを更新しました。
Francesco Casula

なるほど、分かりました。ところで:あなたのコードは間違っています。hasIterationProtocol('')戻る必要がありtrueます!あなたのコードを削除して、反復可能な説明セクションを残してください。それはあなたの答えに真の価値/新しい何かを追加する唯一のものです。
adius

1
それはリターンを行いtrue、私は両方の機能をマージし、厳密な比較を忘れてしまった昔の答えの一部を除去することにより、。今、私は元気だった元の答えを元に戻しました。
Francesco Casula

1
私はObject(...)、素敵なキャッチを使用することを考えたことはなかったでしょう。ただし、その場合はnullチェックは不要です。
ドミノ

2

今日、すでに述べたように、obj反復可能かどうかをテストするには

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

歴史的回答(これ以上有効ではない)

このfor..of構成は、ECMASCript第6版の言語仕様ドラフトの一部です。したがって、最終バージョンの前に変更される可能性があります。

このドラフトでは、反復可能オブジェクトにiteratorプロパティとしての機能が必要です。

オブジェクトが次のように反復可能かどうかを確認できます。

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

7
iteratorプロパティは一時的なFirefoxのものでした。ES6に準拠していません。参照:developer.mozilla.org/en/docs/Web/JavaScript/Reference/...
アミールアラド

2

以下のために非同期イテレータあなたの代わりに「Symbol.iterator」の「Symbol.asyncIterator」をチェックする必要があります。

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

1

変数がオブジェクト({key: value})か配列([value, value])かを実際に確認したい場合は、次のようにします。

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);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.