簡體   English   中英

檢查某事是否可迭代

[英]Checking whether something is iterable

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

for...of構造被描述為能夠迭代“可迭代”對象。 但是有沒有一種好的方法來決定一個對象是否可迭代?

我試圖找到數組、迭代器和生成器的通用屬性,但一直無法做到。

除了在 try 塊中執行for ... of並檢查類型錯誤之外,是否有一種干凈的方法來做到這一點?

檢查可迭代性的正確方法如下:

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 心態。

另外,如果obj是一個字符串,這個函數返回true也不要感到驚訝,因為字符串會遍歷它們的字符。

最簡單的解決方案實際上是這樣的:

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

Object會將任何不是對象的東西包裝成一個,即使原始值不是對象,也允許in運算符工作。 nullundefined被轉換為空對象,因此不需要邊緣情況檢測,並且字符串被包裝成可迭代的 String 對象。

怎么這么啰嗦?

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

作為一個旁注,謹防關於迭代的定義。 如果你來自其他語言,你會期望你可以迭代的東西,比如for循環是iterable 恐怕這里的情況並非如此, iterable意味着實現了迭代協議

為了使事情更清楚,上面的所有示例都在此對象{a: 1, b: 2}上返回false ,因為該對象未實現迭代協議。 所以你不能用for...of迭代它for...of你仍然可以用for...in

因此,如果您想避免痛苦的錯誤,請通過如下所示重命名您的方法來使您的代碼更加具體:

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

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

對於異步迭代器,您應該檢查“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

如果你想檢查一個變量是一個對象( {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);
}

我正在尋找for ... in的支票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

就這樣

const isIterable = !!obj[Symbol.iterator]; // true | false

2021 年末答案

如果您問“是否foo可迭代”,那么您可能來自一種語言(PHP、Python),其中該問題只有一個答案。 在現代 Javascript 中,有不同類型的可迭代對象。 因此,您必須根據要對變量執行的操作來檢查迭代的能力。

TL;DR:對於現代 Javascript 中的大多數用途, Boolean(foo.forEach)會給你你想要的答案。

長答案:讓我們定義一些變量

someNumber = 42;
42

someArray = [1,2,3];
(3) [1, 2, 3]

someString = "Hello";
"Hello, world!"

someObject = {a:"A", b:"B"};
{a: "A", b: "B"}

現在讓我們用forEach檢查它們:

someNumber.forEach;
undefined

someArray.forEach;
ƒ forEach() { [native code] }

someString.forEach;
undefined

someObject.forEach;
undefined

只有Array似乎可以用 forEach 迭代。

現在讓我們用for..in檢查它們:

for (x in someNumber) { console.log(x); }
undefined

for (x in someArray) { console.log(x); }
VM20918:1 0
VM20918:1 1
VM20918:1 2
undefined

for (x in someString) { console.log(x); }
VM20945:1 0
VM20945:1 1
VM20945:1 2
VM20945:1 3
VM20945:1 4
undefined

for (x in someObject) { console.log(x); }
VM20972:1 a
VM20972:1 b
undefined

數組、字符串和對象似乎都可以用for..in迭代。 盡管它沒有迭代,但 Number 沒有拋出錯誤。

現在讓我們用for..of檢查它們:

for (x of someNumber) { console.log(x); }
VM21027:1 Uncaught TypeError: someNumber is not iterable
    at <anonymous>:1:11
    
for (x of someArray) { console.log(x); }
VM21047:1 1
VM21047:1 2
VM21047:1 3
undefined

for (x of someString) { console.log(x); }
VM21065:1 H
VM21065:1 e
VM21065:1 l
VM21065:1 l
VM21065:1 o
undefined

for (x of someObject) { console.log(x); }
VM21085:1 Uncaught TypeError: someObject is not iterable
    at <anonymous>:1:11

數組和字符串似乎可以用 for..of 迭代,但對象不是。 並且 Number 和 Object 都拋出了錯誤。

在現代的 ES6 Javascript 中,我看到forEach使用頻率遠遠高於for..infor..of 但是 Javascript 開發人員必須意識到這三種方法之間的差異,以及每種方法的不同行為。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM