Проверка того, что-то итерабельно
В документах MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
Конструкция for...of
описана так, чтобы иметь возможность перебирать "итерируемые" объекты. Но есть ли хороший способ решить, является ли объект итерабельным?
Я пытался найти общие свойства для массивов, итераторов и генераторов, но не смог этого сделать.
Помимо выполнения for ... of
в блоке try и проверки ошибок типа, существует ли чистый способ сделать это?
Ответы
Ответ 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);
}