JavaScript >> Javascript 文檔 >  >> Tags >> object

如何使用 JavaScript 遞歸遍歷對象

如何編寫一個在對像上查找特定鍵/值對的函數,並遞歸調用該函數以遍歷任意深度的對象。

開始使用

對於本教程,我們將創建一個簡單的單文件 Node.js 項目。在您的計算機上,為您的文件選擇一個合適的位置(例如,項目文件夾)並創建一個名為 index.js 的文件 .

接下來,確保您已在計算機上安裝了 Node.js。雖然我們編寫的代碼不會 依賴 Node.js 工作,我們需要它來運行或執行我們在 index.js 中編寫的代碼 .

創建文件並安裝 Node.js 後,我們就可以開始了。

創建一個函數來通過鍵和值匹配對象

理解遞歸概念的一個簡單方法是想像房子裡的螺旋樓梯。為了從樓梯的頂部走到底部,你需要一步一步走下來。

雖然你是自動完成的,但從技術上講,你的大腦中有一個“功能”,它告訴你如何一步一步走下去,直到你到達底部。您為樓梯中的每個步驟調用該“功能”,直到沒有更多步驟為止。當你往下走時,你告訴“函數”在當前一步之後再次調用它自己。

這就是遞歸在 JavaScript(或任何編程語言)中的工作方式。您編寫一個執行任務的函數,如果該函數不滿足某些要求(例如,查找嵌套值或到達列表末尾),則讓該函數再次調用自身。

在本教程中,我們將編寫一個專注於前者的函數:查找嵌套對象。更具體地說,我們想編寫一個遞歸函數,它可以找到一個嵌套對象,該對象包含具有特定值的特定鍵。

首先,讓我們創建我們的基礎函數並解釋它的作用:

/index.js

const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
  // We'll implement our function here...
};

我們的函數將接受三個參數:一個 object 遍歷,一個 keyToMatch 在該對象內,以及一個 valueToMatch 在那個對象內。

/index.js

const isObject = (value) => {
  return !!(value && typeof value === "object" && !Array.isArray(value));
};

const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
  if (isObject(object)) {
    // We'll work on finding our nested object here...
  }

  return null;
};

接下來,為了避免任何運行時錯誤,在我們的 findNestedObject 的主體中 函數,我們添加一個 if 調用我們在 isObject() 上方添加的新函數的語句 , 傳入 object 傳遞給 findNestedObject 的參數 .

查看 isObject() ,我們想確定我們正在遍歷的對象實際上是一個對象。要找出答案,我們需要驗證傳遞的 value 不為 null 或未定義,具有 typeof “對象”,它是不是 數組。最後一個可能看起來很奇怪。我們需要做 !Array.isArray() 因為在 JavaScript 中,Array s 有一個 typeof “object”(意思是我們之前的typeof value === "object" test 可以被傳遞的數組“欺騙”)。

假設 isObject() 返回 true 對於我們傳遞的值,我們可以開始遍歷對象。如果沒有,作為後備,從我們的 findNestedObject() 我們返回的函數 null 表示我們沒有 找到匹配項。

/index.js

const isObject = (value) => {
  return !!(value && typeof value === "object" && !Array.isArray(value));
};

const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
  if (isObject(object)) {
    const entries = Object.entries(object);

    for (let i = 0; i < entries.length; i += 1) {
      const [treeKey, treeValue] = entries[i];

      if (treeKey === keyToMatch && treeValue === valueToMatch) {
        return object;
      }
    }
  }

  return null;
};

添加一些複雜性,現在,我們要開始遍歷我們的對象。 “遍歷”是指遍歷 object 上的每個鍵/值對 傳入 findNestedObject() .

要執行該循環,我們首先調用 Object.entries() 傳入我們的 object .這將返回一個數組數組,其中每個數組包含 key 當前作為第一個元素和 value 循環的鍵/值對 當前作為第二個元素循環的鍵/值對。像這樣:

const example = {
  first: 'thing',
  second: 'stuff',
  third: 'value',
};

Object.entries(example);

[
  ['first', 'thing'],
  ['second', 'stuff'],
  ['third', 'value']
]

接下來,使用我們的鍵/值對(條目)數組,我們添加一個 for 循環遍歷數組。這裡,i 將等於我們正在循環的當前鍵/值對的索引。我們想要這樣做,直到我們循環了所有的整體,所以我們說“在 i < entries.length 時運行這個循環 對於每次迭代,1 到當前索引 i 。”

for 內部 循環,我們使用 JavaScript 數組解構來訪問當前的鍵/值對數組(用 entries[i] 表示 ),為每個變量分配一個變量。在這裡,我們將第一個元素分配給變量 objectKey 以及變量 objectValue 的第二個元素 .

請記住:我們的目標是通過傳遞的 keyToMatch 找到對象 和 valueToMatch .為了找到匹配項,我們需要檢查 object 上的每個鍵和值 看看他們是否匹配。在這裡,假設我們找到匹配項,我們返回 object 因為它滿足了 keyToMatch 的要求 和 valueToMatch .

添加遞歸遍歷任意深度的對象

現在是有趣的部分。現在,我們的函數只能循環一個單層深度對象。這很棒,但請記住,我們要搜索 nested 目的。因為我們不知道該對象可能在“樹”中的什麼位置(您偶爾會聽到嵌套對像對象的暱稱),所以我們需要能夠“繼續”,如果 key/ 中的值之一值對本身就是一個對象。

這就是我們遞歸的用武之地。

/index.js

const isObject = (value) => {
  return !!(value && typeof value === "object" && !Array.isArray(value));
};

const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
  if (isObject(object)) {
    const entries = Object.entries(object);

    for (let i = 0; i < entries.length; i += 1) {
      const [objectKey, objectValue] = entries[i];

      if (objectKey === keyToMatch && objectValue === valueToMatch) {
        return object;
      }

      if (isObject(objectValue)) {
        const child = findNestedObject(objectValue, keyToMatch, valueToMatch);

        if (child !== null) {
          return child;
        }
      }
    }
  }

  return null;
};

記住我們之前的樓梯類比。在這一點上,我們只走了一步。為了進入下一步,我們需要告訴我們的函數再次調用自己。

在這種情況下,如果傳遞 objectValue,我們知道還有另一個“步驟”或對像要遍歷 到 isObject() 我們之前設置的函數返回 true .如果它確實 ,這意味著我們需要檢查 that 對象包含 keyToMatchvalueToMatch 我們正在尋找。

為了遍歷該對象,我們遞歸地(意思是,再次調用我們當前所在的函數),傳入 objectValue 連同原來的 keyToMatchkeyToValue (我們正在尋找的東西沒有改變,只是我們想要查看的對象)。

如果我們的遞歸調用找到匹配項(意味著我們對 findNestedObject() 的遞歸調用 不是 返回 null ),我們返回那個對象 child .假設我們對 findNestedObject() 的遞歸調用 沒有返回匹配項,我們的遍歷將停止。如果我們的孩子本身有嵌套對象(與我們的類比保持一致,另一個“步驟”要向下走),我們將再次調用 findNestedObject() .

因為這段代碼是遞歸的,所以它會一直運行,直到找到匹配的對象,或者用盡可用的嵌套對象進行搜索。

現在進行測試。讓我們嘗試用 name 在這棵樹中找到對象 字段等於“Down here!”

/index.js

const isObject = (value) => {
  return !!(value && typeof value === "object" && !Array.isArray(value));
};

const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
  if (isObject(object)) {
    const entries = Object.entries(object);

    for (let i = 0; i < entries.length; i += 1) {
      const [objectKey, objectValue] = entries[i];

      if (objectKey === keyToMatch && objectValue === valueToMatch) {
        return object;
      }

      if (isObject(objectValue)) {
        const child = findNestedObject(objectValue, keyToMatch, valueToMatch);

        if (child !== null) {
          return child;
        }
      }
    }
  }

  return null;
};

const staircase = {
  step: 5,
  nextStep: {
    step: 4,
    nextStep: {
      step: 3,
      nextStep: {
        step: 2,
        nextStep: {
          name: "Down here!",
          step: 1,
        },
      },
    },
  },
};

const match = findNestedObject(staircase, "name", "Down here!");
console.log(match);
// { name: "Down here!", step: 1 }

const match2 = findNestedObject(staircase, "step", 3);
console.log(match2);
// { step: 3, nextStep: { step: 2, nextStep: { name: "Down here!", step: 1 } } }

這是實時運行的快速演示:

總結

在本教程中,我們學習瞭如何使用 JavaScript 遞歸遍歷對象。我們學習瞭如何創建一個基本函數,該函數能夠遍歷我們傳遞給它的對象的鍵,尋找匹配的鍵值對。然後,我們學習瞭如何遞歸地使用該函數 ,如果我們當前循環的鍵/值對的值是一個對象,則從其自身內部調用它。


Tutorial JavaScript 教程
  1. 在回顧了 JS 基礎之後,我發現 Create-React-App 做了很多..

  2. Nx 14.2 - Angular v14、Storybook 更新、輕量級 Nx 等等!

  3. 在 jsconfig.json 中使用 baseUrl 不適用於 NextJS

  4. React 18 中的 startTransition 入門

  5. 使用 JavaScript 和 Node.js 編寫魔術卡片技巧

  6. 兩個總和在 javascript 中解決

  7. 用 JavaScript 編寫函數的 5 種方法

  1. Nodejs + TypeScript 樣板

  2. dojo TabContainer 是否有在更改選項卡時觸發的事件?

  3. 使用 Auth0 和 Vue3 構建身份驗證流程

  4. Axios 實例無法與 Nextjs 一起使用:“未定義本地存儲”

  5. 如何使用純 JavaScript 獲取 DIV 元素的 id 和標題

  6. JavaScript 時間戳到 Python 日期時間的轉換

  7. 使用 Next.js 和 TypeScript 破解 Font Awesome 庫以支持自定義圖標

  1. Nix-Shell 如何拯救我們團隊的理智

  2. create-awesome-package :發布了一個 CLI 來引導你很棒的包🚀 📦

  3. 凡事巧奪天工,凡事簡單巧思

  4. 在 Netlify 上部署 React