무언가가 반복 가능한지 확인하기


104

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

for...of구조는 반복 "반복 가능한"오브젝트 할 수 있도록 설명되어 있습니다. 그러나 객체가 반복 가능한지 여부를 결정하는 좋은 방법이 있습니까?

배열, 반복기 및 생성기에 대한 공통 속성을 찾으려고했지만 그렇게 할 수 없었습니다.

for ... oftry 블록에서 수행하고 유형 오류를 확인하는 것 외에이 작업을 수행하는 깨끗한 방법이 있습니까?


확실히 저자로서 당신의 객체가 반복 가능한지 알고 있습니까?
andrewb

5
개체는 인수로 전달되지만 확실하지 않습니다.
simonzack

1
인수의 typeof를 테스트하지 않는 이유는 무엇입니까?
James Bruckner

2
@ andrew-buchan, James Bruckner : 유형 확인은 작동 할 수 있지만 MDN 문서를 읽으면 "배열과 유사"라는 것을 알 수 있습니다. 이것이 정확히 무엇을 의미하는지 모르겠습니다. 따라서 질문입니다.
simonzack

1
wiki.ecmascript.org/doku.php?id=harmony:iterators 는 " 메소드가있는 객체는 반복 할 수 있습니다 iterator(). "라고 말합니다. 그러나 이것은 초안이기 때문에 수표 만 구현에 따라 달라질 수 있습니다. 어떤 환경을 사용하십니까?
Bergi

답변:


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'연산자 사용에는 (적어도) 하나의 예외가 있습니다 : 문자열. 문자열은 반복 가능하지만 (for..of 측면에서) 'in'을 사용할 수 없습니다. 이것이 아니라면 'in'을 사용하는 것이 더 좋을 것 같습니다.
Tomas Kulich 2015

return typeof obj[Symbol.iterator] === 'function'그래? "순서가 반복 가능한 일에, 객체는 @@ 반복자 방법을 구현해야합니다"-이 방법 지정
캘럼

obj [Symbol.iterator]가 (정의되지 않은 또는) 함수 이외의 다른 의미는 없습니다. 누군가 예를 들어 String을 거기에 넣으면 나쁜 일이고 IMO는 코드가 가능한 한 빨리 실패하면 좋습니다.
Tomas Kulich

겠습니까 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 2011

26
하하, 일반적으로 나는 읽을 수없는 코드에 대해 불평하는 사람이지만 실제로 이것은 꽤 읽기 쉽다고 생각합니다. 영어 문장처럼 : 객체가 null이 아니고 기호 반복기 속성이 함수이면 반복 가능합니다. 그 죽은 간단한 아니라면, 나는 ... 무엇인지 모른다
adius가

4
IMO, "가독성"의 포인트는없이 무슨 일이 일어나고 있는지 이해하는 것입니다 실제 읽기
드미트리 Parzhitsky

2
@Alexander Mills 귀하의 개선으로 코드가 악화되었습니다. 1. @jfmercer가 말했듯 Readability > Cleverness이 변수 objecto줄여 아무도 도움이되지 않습니다. 2. 빈 문자열 ''은 반복 가능하므로를 반환해야합니다 true.
adius

1
알겠습니다. 사용하는 이유가 있다고 생각했습니다!= null
Alexander Mills

22

가장 간단한 해결책은 실제로 다음과 같습니다.

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

Objectin원래 값이 Object가 아니더라도 연산자가 작업 할 수 있도록 개체가 아닌 모든 것을 하나로 묶습니다. nullundefined에지의 경우 탐지를위한 필요가 없습니다 있도록 빈 개체로 설정하고, 문자열을 반복 가능한이다 String 객체에 랩 얻을.


1
잘못된 기호를 사용했습니다. 그것은 : Symbol.iterator.
Gil

@Gil 당신이 절대적으로 맞습니다, 죄송합니다! 게시물에 직접 입력하는 대신 테스트 코드를 복사하여 붙여 넣어야합니다.
Domino

Object이러한 유형의 검사 에서는로 새 개체를 만드는 것이 낭비입니다.
Ruben Verborgh

Object함수가 어떻게 구현 되었는지 정확히 알 수 value는 없지만, 이미 객체가 아닌 경우에만 새 객체를 생성합니다 . 나는의 조합을 기대 in하고 Object(...)말과는 달리, 쉽게 최적화 뭔가 브라우저 엔진으로 value !== undefined && value !== null && value[Symbol.iterator] && true. 또한 매우 가독성이 좋아서 신경 쓰고 있습니다.
Domino

9

(!) 참고로, 조심 의 정의에 대해 반복 가능한 . 다른 언어에서 온 경우 반복 할 수있는 무언가를 기대할 수 있습니다. 예를 들어 for루프는 반복 가능 합니다. 나는 iterable반복 프로토콜 을 구현하는 것을 의미 하는 경우가 아닙니다 .

더 명확하게하기 위해 위의 모든 예제 false는이 객체 {a: 1, b: 2}가 반복 프로토콜을 구현하지 않기 때문에이 객체를 반환 합니다. 당신은 그것을 반복 할 수 없습니다 그래서 for...of 하지만 당신은 여전히 A를 할 수 있습니다 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 2011

알 겠어. Btw : 코드가 올바르지 않습니다. hasIterationProtocol('')반환해야합니다 true! 코드를 제거하고 반복 가능한 설명 섹션을 남겨 두는 것은 어떻습니까? 이것은 답변에 실제 가치 / 새로운 것을 추가하는 유일한 것입니다.
adius

1
그것은 반환하지 true내가 두 기능을 통합하고 엄격한 비교 잊어 이전 대답의 일부를 제거하여,. 이제 잘 작동하는 원래 답변을 다시 넣었습니다.
Francesco Casula 2011

1
Object(...), nice catch 를 사용할 생각은 없었을 것 입니다. 그러나이 경우 null 검사가 필요하지 않습니다.
Domino

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 속성은 일시적인 파이어 폭스였습니다. 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.