Подтвердить что ты не робот

Проверка того, что-то итерабельно

В документах MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of

Конструкция for...of описана так, чтобы иметь возможность перебирать "итерируемые" объекты. Но есть ли хороший способ решить, является ли объект итерабельным?

Я пытался найти общие свойства для массивов, итераторов и генераторов, но не смог этого сделать.

Помимо выполнения for ... of в блоке try и проверки ошибок типа, существует ли чистый способ сделать это?

4b9b3361

Ответ 1

Правильный способ проверки итерации заключается в следующем:

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

Поскольку мы говорим о... я полагаю, мы настроены на ES6.

Кроме того, не удивляйтесь, что эта функция возвращает true если obj является строкой, поскольку строки перебирают свои символы.

Ответ 2

Почему так многословно?

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

Ответ 3

Как примечание, ОСТЕРЕГАЙТЕСЬ об определении повторяемости. Если вы работаете с другими языками, вы можете ожидать, что то, что вы можете перебрать с помощью, скажем, цикла for является итеративным. Я боюсь, что не тот случай, когда итерируемый означает что-то, что реализует протокол итерации.

Для ясности все приведенные выше примеры возвращают false для этого объекта {a: 1, b: 2} поскольку этот объект не реализует протокол итерации. Таким образом, вы не сможете перебрать его с помощью for...of НО, но вы все еще можете сделать это с помощью for...in.

Поэтому, если вы хотите избежать болезненных ошибок, сделайте свой код более конкретным, переименовав свой метод, как показано ниже:

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

Ответ 4

Самое простое решение на самом деле это:

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

Object обернет все, что не является объектом в одном, что позволяет оператору in работать, даже если исходное значение не является Object. null и undefined превращаются в пустые объекты, поэтому нет необходимости в обнаружении краевого случая, а строки переносятся в объекты String, которые можно повторять.

Ответ 5

В настоящее время, как уже было сказано, чтобы проверить, является ли obj итерабельным, просто выполните

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

Исторический ответ (не более)

Конструкция for..of является частью проекта спецификации спецификации ECMASCript 6-го издания. Поэтому он может измениться до окончательной версии.

В этом проекте iterable объекты должны иметь функцию iterator как свойство.

Вы можете проверить, можно ли истребить объект следующим образом:

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

Ответ 6

Для асинхронных итераторов вы должны проверить "Symbol.asyncIterator" вместо "Symbol.iterator":

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

Ответ 7

Если вы действительно хотите проверить, является ли переменная объектом ({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);
}