最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JS 樹(shù)與數(shù)組相互轉(zhuǎn)換的幾種方法

 更新時(shí)間:2026年02月24日 09:43:14   作者:發(fā)現(xiàn)一只大呆瓜  
本文主要介紹了JS 樹(shù)與數(shù)組相互轉(zhuǎn)換的幾種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

在前端業(yè)務(wù)中,后端返回的扁平化數(shù)組(Array)往往需要轉(zhuǎn)換為樹(shù)形結(jié)構(gòu)(Tree)來(lái)適配 UI 組件(如 Element UI 的 Tree 或 Cascader)。掌握多種轉(zhuǎn)換思路及性能差異,是進(jìn)階高級(jí)前端的必備技能。

一、 核心概念:結(jié)構(gòu)對(duì)比

數(shù)組結(jié)構(gòu):每一項(xiàng)通過(guò) parentId 指向父級(jí)。

  const nodes = [
    { id: 3, name: '節(jié)點(diǎn)C', parentId: 1 },
    { id: 6, name: '節(jié)點(diǎn)F', parentId: 3 },
    { id: 0, name: 'root', parentId: null },
    { id: 1, name: '節(jié)點(diǎn)A', parentId: 0 },
    { id: 8, name: '節(jié)點(diǎn)H', parentId: 4 },
    { id: 4, name: '節(jié)點(diǎn)D', parentId: 1 },
    { id: 2, name: '節(jié)點(diǎn)B', parentId: 0 },
    { id: 5, name: '節(jié)點(diǎn)E', parentId: 2 },
    { id: 7, name: '節(jié)點(diǎn)G', parentId: 2 },
    { id: 9, name: '節(jié)點(diǎn)I', parentId: 5 },
  ];

樹(shù)形結(jié)構(gòu):父級(jí)通過(guò) children 數(shù)組包裹子級(jí)。

  let tree = [
    {
      id: 1,
      name: 'text1',
      parentId: 1,
      children: [
        {
          id: 2,
          name: 'text2',
          parentId: 1,
          children: [
            {
              id: 4,
              name: 'text4',
              parentId: 2,
            },
          ],
        },
        {
          id: 3,
          name: 'text3',
          parentId: 1,
        },
      ],
    },
  ];

二、 數(shù)組轉(zhuǎn)樹(shù)

1. 遞歸思路

原理

  1. 首先需要傳遞給函數(shù)兩個(gè)參數(shù):數(shù)組、當(dāng)前的父節(jié)點(diǎn)id
  2. 設(shè)置一個(gè)結(jié)果數(shù)組res,遍歷數(shù)組,先找到子元素的父節(jié)點(diǎn)id與父節(jié)點(diǎn)id一致的子項(xiàng)
  3. 將這個(gè)子項(xiàng)的id作為父節(jié)點(diǎn)id傳入函數(shù),繼續(xù)遍歷
  4. 將遍歷的結(jié)果作為children返回,并給當(dāng)前項(xiàng)添加children
  5. 將這個(gè)當(dāng)前項(xiàng),插入到res里面,并返回

注意:如果不想影響原數(shù)組,需要先深拷貝一下數(shù)組。const cloneArr = JSON.parse(JSON.stringify (arr))

  const nodes = [
    { id: 3, name: '節(jié)點(diǎn)C', parentId: 1 },
    { id: 6, name: '節(jié)點(diǎn)F', parentId: 3 },
    { id: 0, name: 'root', parentId: null },
    { id: 1, name: '節(jié)點(diǎn)A', parentId: 0 },
    { id: 8, name: '節(jié)點(diǎn)H', parentId: 4 },
    { id: 4, name: '節(jié)點(diǎn)D', parentId: 1 },
    { id: 2, name: '節(jié)點(diǎn)B', parentId: 0 },
    { id: 5, name: '節(jié)點(diǎn)E', parentId: 2 },
    { id: 7, name: '節(jié)點(diǎn)G', parentId: 2 },
    { id: 9, name: '節(jié)點(diǎn)I', parentId: 5 },
  ];
  //遞歸寫(xiě)法
  const arrToTree1 = (arr, id) => {
    const res = [];
    arr.forEach((item) => {
      if (item.parentId === id) {
        const children = arrToTree1(arr, item.id);
        //如果希望每個(gè)元素都有children屬性,可以直接賦值
        if (children.length !== 0) {
          item.children = children;
        }
        res.push(item);
      }
    });
    return res;
  };
  console.log(arrToTree1(nodes, null));

2. 非遞歸思路

原理:利用 filter 進(jìn)行二次篩選。雖然寫(xiě)法簡(jiǎn)潔,但在大數(shù)據(jù)量下性能較差(O(n2)O(n^2)O(n2))。

  1. 函數(shù)只需要接受一個(gè)參數(shù),也就是需要轉(zhuǎn)換的數(shù)組arr
  2. 第一層過(guò)濾數(shù)組,直接返回一個(gè)parentId為根id的元素
  3. 但是在返回之間,需要再根據(jù)當(dāng)前id過(guò)濾里面的每一項(xiàng)(過(guò)濾規(guī)則為如果子項(xiàng)的paentId為當(dāng)前的id,則在當(dāng)前項(xiàng)的children插入這個(gè)子項(xiàng))
  const arrToTree2 = (arr) => {
    return arr.filter((father) => {
      const childrenArr = arr.filter((children) => {
        return children.parentId === father.id;
      });
      //如果希望每個(gè)元素都有children屬性,可以直接賦值
      if (childrenArr.length !== 0) {
        father.children = childrenArr;
      }
      return father.parentId === null;
    });
  };
  console.log(arrToTree2(nodes));

3. Map 對(duì)象方案(O(n)O(n)O(n)時(shí)間復(fù)雜度)

原理:利用對(duì)象的引用性質(zhì)。先將數(shù)組轉(zhuǎn)為 Map,再遍歷一次即可完成。這是在大數(shù)據(jù)量下的首選方案。

  const arrToTree3 = (arr) => {
    const map = {};
    const res = [];

    // 1. 建立映射表
    arr.forEach((item) => {
      map[item.id] = { ...item, children: [] };
    });

    // 2. 組裝樹(shù)結(jié)構(gòu)
    arr.forEach((item) => {
      const node = map[item.id];
      if (item.parentId === null) {
        res.push(node);
      } else {
        if (map[item.parentId]) {
          map[item.parentId].children.push(node);
        }
      }
    });
    return res;
  };
  console.log(arrToTree3(nodes));

三、 樹(shù)轉(zhuǎn)數(shù)組

1. 遞歸遍歷思路

原理:定義一個(gè)結(jié)果數(shù)組,遞歸遍歷樹(shù)的每一層,將節(jié)點(diǎn)信息(排除 children)推入數(shù)組。

  1. 首先定義一個(gè)結(jié)果數(shù)組res,遍歷傳入的樹(shù)
  2. 直接將當(dāng)前項(xiàng)的id、name、parentId包裝在一個(gè)新對(duì)象里插入
  3. 判斷是否有children屬性,如果有則遍歷children屬性每一項(xiàng),繼續(xù)執(zhí)行2、3步驟
  let tree = [
    {
      id: 1,
      name: 'text1',
      parentId: 1,
      children: [
        {
          id: 2,
          name: 'text2',
          parentId: 1,
          children: [
            {
              id: 4,
              name: 'text4',
              parentId: 2,
            },
          ],
        },
        {
          id: 3,
          name: 'text3',
          parentId: 1,
        },
      ],
    },
  ];
  const treeToArr = (tree) => {
    const res = [];
    tree.forEach((item) => {
      const loop = (data) => {
        res.push({
          id: data.id,
          name: data.name,
          parseId: data.parentId,
        });
        if (data.children) {
          data.children.forEach((itemChild) => {
            loop(itemChild);
          });
        }
      };
      loop(item);
    });
    return res;
  };
  console.log(treeToArr(tree));

四、 注意事項(xiàng):深拷貝的必要性

在處理這些轉(zhuǎn)換時(shí),由于 JS 的對(duì)象是引用類(lèi)型,直接修改 item.children 會(huì)改變?cè)紨?shù)組的內(nèi)容。

  • 快捷方案:const cloneArr = JSON.parse(JSON.stringify(arr))。
  • 避坑點(diǎn):如果數(shù)組項(xiàng)中包含 Date 對(duì)象、RegExp 或 Function,JSON.parse 會(huì)導(dǎo)致數(shù)據(jù)失真,此時(shí)應(yīng)使用其他深拷貝方案。

到此這篇關(guān)于JS 樹(shù)與數(shù)組相互轉(zhuǎn)換的幾種方法的文章就介紹到這了,更多相關(guān)JS 樹(shù)與數(shù)組相互轉(zhuǎn)換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • 詳解JavaScript如何實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Promise對(duì)象

    詳解JavaScript如何實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Promise對(duì)象

    Promise對(duì)象的作用將異步操作以同步操作的流程表達(dá)出來(lái),避免層層嵌套的回調(diào)函數(shù),而且Promise提供了統(tǒng)一的接口,使得控制異步操作更加容易。本文介紹了如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Promise對(duì)象,需要的可以參考一下
    2022-11-11
  • Bootstrap 附加導(dǎo)航(Affix)插件實(shí)例詳解

    Bootstrap 附加導(dǎo)航(Affix)插件實(shí)例詳解

    附加導(dǎo)航(Affix)插件允許某個(gè) <div> 固定在頁(yè)面的某個(gè)位置。接下來(lái)通過(guò)本文給大家介紹Bootstrap 附加導(dǎo)航(Affix)插件實(shí)例詳解,感興趣的朋友一起看看吧
    2016-06-06
  • 如何解決IONIC頁(yè)面底部被遮住無(wú)法向上滾動(dòng)問(wèn)題

    如何解決IONIC頁(yè)面底部被遮住無(wú)法向上滾動(dòng)問(wèn)題

    Ionic 是目前最有潛力的一款 HTML5 手機(jī)應(yīng)用開(kāi)發(fā)框架。在開(kāi)發(fā)過(guò)程中我們同樣會(huì)遇到各種各樣奇葩的問(wèn)題。下面小編給大家?guī)?lái)了有關(guān)IONIC頁(yè)面底部被遮住無(wú)法向上滾動(dòng)問(wèn)題的解決方案
    2016-09-09
  • 一文詳解JSON.parse和JSON.stringify的用法

    一文詳解JSON.parse和JSON.stringify的用法

    Json.stringify()和toString()兩者雖然都可以講目標(biāo)值轉(zhuǎn)為字符串,但是還是有本質(zhì)區(qū)別的,下面這篇文章主要給大家介紹了關(guān)于JSON.parse和JSON.stringify用法的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • 淺談JS中this在各個(gè)場(chǎng)景下的指向

    淺談JS中this在各個(gè)場(chǎng)景下的指向

    這篇文章主要介紹了淺談JS中this在各個(gè)場(chǎng)景下的指向,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • IE下通過(guò)a實(shí)現(xiàn)location.href 獲取referer的值

    IE下通過(guò)a實(shí)現(xiàn)location.href 獲取referer的值

    IE下采用window.location.href方式跳轉(zhuǎn)的話,referer值為空在標(biāo)簽a里面的跳轉(zhuǎn)的話referer就不會(huì)空,下面是具體的實(shí)現(xiàn)代碼
    2014-09-09
  • javaScript中的空值和假值

    javaScript中的空值和假值

    JavaScript 是世界上最流行的編程語(yǔ)言。javaScript中有五種空值和假值,分別為false,null,undefined,“”,0。從廣義上來(lái)說(shuō),這五個(gè)值都是對(duì)應(yīng)數(shù)據(jù)類(lèi)型的無(wú)效值或空值
    2017-12-12
  • uniapp開(kāi)發(fā)小程序?qū)崿F(xiàn)全局懸浮按鈕的代碼

    uniapp開(kāi)發(fā)小程序?qū)崿F(xiàn)全局懸浮按鈕的代碼

    這篇文章主要介紹了uniapp開(kāi)發(fā)小程序如何實(shí)現(xiàn)全局懸浮按鈕,但是在uniapp中式?jīng)]有window對(duì)象,和dom元素的,需要獲取頁(yè)面上節(jié)點(diǎn)的幾何信息,具體實(shí)例代碼詳細(xì)跟隨小編一起看看吧
    2022-03-03
  • javascript 封裝Date日期類(lèi)實(shí)例詳解

    javascript 封裝Date日期類(lèi)實(shí)例詳解

    這篇文章主要介紹了javascript-封裝Date日期類(lèi)的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • layui使用label標(biāo)簽的方法

    layui使用label標(biāo)簽的方法

    今天小編就為大家分享一篇layui使用label標(biāo)簽的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-09-09

最新評(píng)論

六安市| 龙岩市| 蒙阴县| 凤山市| 满城县| 错那县| 永善县| 威远县| 松阳县| 栾城县| 永城市| 武威市| 呼玛县| 察隅县| 铁岭市| 济阳县| 锦屏县| 集安市| 郧西县| 兴文县| 榕江县| 比如县| 遂昌县| 余江县| 临高县| 祁连县| 伊通| 保德县| 宁夏| 江川县| 宽甸| 惠东县| 瓦房店市| 将乐县| 仪征市| 拜泉县| 鱼台县| 南投县| 崇义县| 堆龙德庆县| 沁水县|