检查某些内容是否可迭代

时间:2013-09-18 23:56:38

标签: javascript

在MDN文档中:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of

for...of构造被描述为能够迭代“可迭代”对象。但有没有一种很好的方法来判断一个对象是否可以迭代?

我试图找到数组,迭代器和生成器的公共属性,但一直无法这样做。

除了在try块中执行for ... of并检查类型错误之外,还有一种干净的方法吗?

8 个答案:

答案 0 :(得分:92)

检查可迭代性的正确方法如下:

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并不会感到惊讶,因为字符串会迭代它们的字符。

答案 1 :(得分:15)

为什么这么详细?

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

答案 2 :(得分:6)

作为旁注,请注意关于可迭代的定义。如果您来自其他语言,那么您可以期待可以迭代的内容,例如,for循环可迭代。我担心这里的情况不是可迭代意味着实现iteration protocol的东西。

为了使事情更清楚,上面的所有示例都会在此对象false上返回{a: 1, b: 2},因为该对象未实现迭代协议。因此,您无法使用for...of 对其进行迭代,您仍然可以使用for...in

因此,如果您想避免痛苦的错误,请通过重命名您的方法使您的代码更具体,如下所示:

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

答案 3 :(得分:3)

最简单的解决方案实际上是这样的:

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

Object将所有不是对象的东西包装在一起,即使原始值不是对象,也允许in运算符工作。 nullundefined变成了空对象,因此不需要边缘情况检测,并且字符串被包装成可迭代的String对象。

答案 4 :(得分:2)

如今,如前所述,要测试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;
}

答案 5 :(得分:1)

对于异步迭代器,您应该检查'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

答案 6 :(得分:0)

如果您实际上想检查变量是对象({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);
}

答案 7 :(得分:0)

我一直在寻找for ... in的支票,并决定了以下内容。

isIterable (value) {
  // add further checks here based on need.
  return Object.keys(Object(value)).length > 0
}

对于所有可迭代且具有至少一个值的值,它将返回true。 因此,空字符串,空数组,空对象等将返回false。 但是{a: 'x', b:'y'}将返回true