Checking whether something is iterable

后端 未结 8 904
甜味超标
甜味超标 2020-11-28 04:55

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

The for...of construct is described to be able to

相关标签:
8条回答
  • 2020-11-28 05:00

    I was looking for a check for for ... in and decided on the following.

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

    This will return true for anything that is iterable and has at least one value. Therefore empty strings, empty arrays, empty objects etc. will return false. But {a: 'x', b:'y'} will return true.

    0 讨论(0)
  • 2020-11-28 05:01

    The simplest solution is actually this:

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

    Object will wrap anything which isn't an object in one, allowing the in operator to work even if the original value is not an Object. null and undefined are turned into empty objects so there's no need for edge case detection, and strings get wrapped into String objects which are iterable.

    0 讨论(0)
  • 2020-11-28 05:01

    Why so verbose?

    const isIterable = object =>
      object != null && typeof object[Symbol.iterator] === 'function'
    
    0 讨论(0)
  • 2020-11-28 05:13

    As a sidenote, BEWARE about the definition of iterable. If you're coming from other languages you would expect that something you can iterate over with, say, a for loop is iterable. I'm afraid that's not the case here where iterable means something that implements the iteration protocol.

    To make things clearer all examples above return false on this object {a: 1, b: 2} because that object does not implement the iteration protocol. So you won't be able to iterate over it with a for...of BUT you still can with a for...in.

    So if you want to avoid painful mistakes make your code more specific by renaming your method as shown below:

    /**
     * @param variable
     * @returns {boolean}
     */
    const hasIterationProtocol = variable =>
        variable !== null && Symbol.iterator in Object(variable);
    
    0 讨论(0)
  • 2020-11-28 05:16

    If you wanted to check in fact if a variable is an object ({key: value}) or an array ([value, value]), you could do that:

    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);
    }
    
    0 讨论(0)
  • 2020-11-28 05:18

    The proper way to check for iterability is as follows:

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

    Why this works (iterable protocol in depth): https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols

    Since we are talking about for..of, I assume, we are in ES6 mindset.

    Also, don't be surprised that this function returns true if obj is a string, as strings iterate over their characters.

    0 讨论(0)
提交回复
热议问题