JS中树形对象与数组之间的相互转换

在工作中经常会遇到树形结构的对象转为数组或者数组转为树形对象的需求,那么如何实现呢?

1、首先是要将一个具有树形结构的数组转化为树形结构的对象

// 将一个扁平化的对象数组,转化为树形结构
// 现在有一个对象组成的数组,每个元素有id属性和parent_id属性,根据其id属性和parent_id属性,将其转换为树结构的对象
const arr = [
   {
       id: ‘1‘,
       parent_id: ‘root‘,
       name:‘abc‘
   },
   {
       id: ‘2‘,
       parent_id: ‘root‘,
       name:‘abc‘
   },
   {
       id: ‘1-1‘,
       parent_id: ‘1‘,
       name:‘abc‘
   },
   {
       id: ‘1-2‘,
       parent_id: ‘1‘,
       name:‘abc‘
   },
   {
       id: ‘1-1-1‘,
       parent_id: ‘1-1‘,
       name:‘abc‘
   },
   {
       id: ‘1-1-2‘,
       parent_id: ‘1-1‘,
       name:‘abc‘
   },
   {
       id: ‘1-2-1‘,
       parent_id: ‘1-2‘,
       name:‘abc‘
   },
   {
       id: ‘2-1‘,
       parent_id: ‘2‘,
       name:‘abc‘
   },
   {
       id: ‘2-2‘,
       parent_id: ‘2‘,
       name:‘abc‘
   },
   {
       id: ‘2-1-1‘,
       parent_id: ‘2-1‘,
       name:‘abc‘
   },
   {
       id: ‘2-2-1‘,
       parent_id: ‘2-2‘,
       name:‘abc‘
   },
   {
       id: ‘2-2-1-1‘,
       parent_id: ‘2-2-1‘,
       name:‘abc‘
   },
   {
       id: ‘2-2-1-2‘,
       parent_id: ‘2-2-1‘,
       name:‘abc‘
   },
    {
       id: ‘2-2-1-2-1‘,
       parent_id: ‘2-2-1-2‘,
       name:‘abc‘
   },
   {
       id: ‘2-3‘,
       parent_id: ‘2‘,
       name:‘abc‘
   },
   {
       id: ‘2-3-1‘,
       parent_id: ‘2-3‘,
       name:‘abc‘
   },
   {
       id: ‘3‘,
       parent_id: ‘root‘,
       name:‘abc‘
   },
];

// 将这样一个数组,变成能够以树形展示的对象

//先将数组中的每一个节点放到temp对象中(创建set)
//即数组中有{id: ‘2-3‘, parent_id: ‘2‘,...}这样一个节点,需要将他放到temp中变成 ‘2-3‘: {id: ‘2-3‘, parent_id: ‘2‘,...}这种JSON结构
//直接遍历整个temp对象,通过这句代码   temp[temp[i].parent_id].children[temp[i].id] = temp[i]; 
//将当前子节点与父节点建立连接。是因为我们保证了父节点一定在子节点前,
//那么当子节点出现的时候就直接可以用temp[temp[i].parent_id]来查找到父节点这个时候先父节点的children对象中添加一个引用即可。

function buildTree(array,id,parent_id) {
    console.time(‘123‘);
    // 创建临时对象
    let temp = {};
    // 创建需要返回的树形对象
    let tree = {};
    // 先遍历数组,将数组的每一项添加到temp对象中
    for(let i in array) {
        temp[array[i][id]] = array[i];
    }

    /*  上面也可以写成
    for(let i=0;i<array.length;i++) {
        temp[array[i][id]] = array[i];
    }
    */

    // 遍历temp对象,将当前子节点与父节点建立连接
    for(let i in temp) {
        // 判断是否是根节点下的项
        if(temp[i][parent_id] !== ‘root‘) {
             if(!temp[temp[i][parent_id]].children) {
                 temp[temp[i][parent_id]].children = new Array();
             }
             temp[temp[i][parent_id]].children.push(temp[i]);
        } else {
            tree[temp[i][id]] = temp[i];
        }
    }

    /*  上面也可以写成
    for(let i=0;i<array.length;i++) {
        temp[array[i][id]] = array[i];
    }
    */

    console.timeEnd(‘123‘);
    return tree;
}

const obj = buildTree(arr, ‘id‘, ‘parent_id‘);
console.log(obj);

2、树形结构转化为一维扁平数组

const treeObj = {
    id: ‘0‘,
    name: ‘0‘,
    children:[
        {
            id: ‘1‘,
            name:‘anc‘,
            children:[
                 {
                    id: ‘1-1‘,
                    name:‘anc‘,
                    children:[
                        {
                            id: ‘1-1-1‘,
                            name:‘anc‘,
                        },
                        {
                            id: ‘1-1-2‘,
                            name:‘anc‘
                        },
                    ]
                },
                {
                    id: ‘1-2‘,
                    name:‘anc‘,
                    children:[
                        {
                            id: ‘1-2-1‘,
                            name:‘anc‘,
                        },
                        {
                            id: ‘1-2-2‘,
                            name:‘anc‘
                        },
                    ]
                },
            ]
        },
        {
            id: ‘2‘,
            name:‘anc‘,
            children:[
                 {
                    id: ‘2-1‘,
                    name:‘anc‘,
                    children:[
                        {
                            id: ‘2-1-1‘,
                            name:‘anc‘,
                        },
                        {
                            id: ‘2-1-2‘,
                            name:‘anc‘
                        },
                    ]
                },
                {
                    id: ‘2-2‘,
                    name:‘anc‘,
                    children:[
                        {
                            id: ‘2-2-1‘,
                            name:‘anc‘,
                            children: [
                                {
                                    id: ‘2-2-1-1‘,
                                    name:‘anc‘,
                                },
                                {
                                    id: ‘2-2-1-2‘,
                                    name:‘anc‘
                                },
                            ]
                        },
                        {
                            id: ‘2-2-2‘,
                            name:‘anc‘
                        },
                    ]
                },
                {
                    id: ‘2-3‘,
                    name:‘anc‘,
                    children:[
                        {
                            id: ‘2-3-1‘,
                            name:‘anc‘,
                        },
                        {
                            id: ‘2-3-2‘,
                            name:‘anc‘
                        },
                    ]
                },
            ]
        },
        {
            id: ‘3‘,
            name:‘anc‘,
            children:[]
        }
    ]
};
// 将treeObj中的所有对象,放入一个数组中,要求某个对象在另一个对象的children时,其parent_id是对应的另一个对象的id
// 其原理实际上是数据结构中的广度优先遍历

function tree2Array(treeObj, rootid) {
   const temp = [];  // 设置临时数组,用来存放队列
   const out = [];    // 设置输出数组,用来存放要输出的一维数组
   temp.push(treeObj);
   // 首先把根元素存放入out中
   let pid = rootid;
   const obj = deepCopy(treeObj);
   obj.pid = pid;
   delete obj[‘children‘];
   out.push(obj)
   // 对树对象进行广度优先的遍历
   while(temp.length > 0) {
       const first = temp.shift();
       const children = first.children;
       if(children && children.length > 0) {
           pid = first.id;
           const len = first.children.length;
           for(let i=0;i<len;i++) {
               temp.push(children[i]);
               const obj = deepCopy(children[i]);
               obj.pid = pid;
               delete obj[‘children‘];
               out.push(obj)
           }
       }
   }
   return out
}

console.log(tree2Array(treeObj, ‘root‘))

// 深拷贝
function deepCopy(obj){
    // 深度复制数组
    if(Object.prototype.toString.call(obj) === "[object Array]"){
      const object=[];
      for(let i=0;i<obj.length;i++){
        object.push(deepCopy(obj[i]))
      }
      return object
    }
    // 深度复制对象
    if(Object.prototype.toString.call(obj) === "[object Object]"){
      const object={};
      for(let p in obj){
        object[p]=obj[p]
      }
      return object
    }
}

原文地址:https://www.cnblogs.com/liquanjiang/p/11405480.html

时间: 2024-10-14 07:30:43

JS中树形对象与数组之间的相互转换的相关文章

在JS中,对象和数组的区别理解

学习js一段时间,一度搞不清楚“数组”和对象的根本区别.二者都可以用来表示数据的集合. 比如说一个数组是a=[1,2,3,4],一个对象是a={0:1,1:2,2:3,3:4} 输出alert(a[1]),二者的输出结果相同.花了一点时间整理了我对对象和数组的理解. 区别一: 数组是有序数据的集合,而对象是无序数据的集合. 区别二: 数组的数据没有名称,只有下标,而对象的数据需要指定名称. 学过其他语言的人可能会提出“关联数组“是可以有名称的. 比如在js中,可以这样定义一个关联数组: a[“城

JS中判断对象是不是数组的方法

JavaScript中检测对象的方法 1.typeof操作符 这种方法对于一些常用的类型来说那算是毫无压力,比如Function.String.Number.Undefined等,但是要是检测Array的对象就不起作用了. 利用typeof除了array和null判断为object外,其他的都可以正常判断 alert(typeof null); // "object" alert(typeof function () { return 1; }); // "function&

JavaScript学习12 JS中定义对象的几种方式【转】

avaScript学习12 JS中定义对象的几种方式 转自:  http://www.cnblogs.com/mengdd/p/3697255.html JavaScript中没有类的概念,只有对象. 在JavaScript中定义对象可以采用以下几种方式: 1.基于已有对象扩充其属性和方法 2.工厂方式 3.构造函数方式 4.原型("prototype")方式 5.动态原型方式 一.基于已有对象扩充其属性和方法 <script type="text/javascript

JavaScript学习12 JS中定义对象的几种方式

JavaScript学习12 JS中定义对象的几种方式 JavaScript中没有类的概念,只有对象. 在JavaScript中定义对象可以采用以下几种方式: 1.基于已有对象扩充其属性和方法 2.工厂方式 3.构造函数方式 4.原型("prototype")方式 5.动态原型方式 一.基于已有对象扩充其属性和方法 <script type="text/javascript"> var object = new Object(); object.name

浅解析js中的对象

浅解析js中的对象 说到对象,我首先想到的是每逢过年过节,长辈们老是开玩笑的问我“你找了对象没?”.不说大家都知道,这里的“对象”指的是“女朋友”,但是今天我想要说的js中的“对象”和我们生活中谈到的“对象”不是同一回事,但是其中也有着很多相似之处.    在讲js中的对象之前,我想先抛出几个疑问:    什么是对象?    对象有哪些?    对象能做什么?    如何创建对象?    如何对对象进行操作?    对象有特性么?有的话有哪些特性?    对象有属性么?有的话有哪些?对属性如何操

js中推断对象详细类型

大家可能知道js中推断对象类型能够用typeof来推断. 看以下的情况 <script> alert(typeof 1);//number alert(typeof "2");//string alert(typeof [1,2,3]);//object alert(typeof {"name":"zhuhui"})//object </script> 从上面中我们能够看出数组和普通对象用typeof推断出来都是objec

js中window对象详解以及页面跳转

js中window对象详解以及页面跳转 转自:http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E6%90%9C/39219.shtml 1.window.top.window.location = "index.asp"; 2.window.top.location.href="index.asp" 3. window.top.location.replace("index.asp");

JS中有关对象的继承以及实例化、浅拷贝深拷贝的奥秘

一.属性的归属问题 JS对象中定义的属性和方法如果不是挂在原型链上的方法和属性(直接通过如类似x的方式进行定义)都只是在该对象上,对原型链上的没有影响.对于所有实例共用的方法可直接定义在原型链上这样实例化的的时候就不用对每个实例定义该属性方法,所有的实例均具有该方的引用见最后的输出. function Myclass(){ this.x=" x in Myclass"; this.get=function(){}//每次实例化对象,每个对象的该方法都是独立的,是不相同的 } Mycla

JS中的对象和方法简单剖析

众所周知,在js中对象就是精髓,不理解对象就是不理解js. 那么什么事js中的对象呢? 在js中,几乎一切皆对象: Boolean ,String,Number可以是对象(或者说原生数据被认作对象): Dates ,Maths,Regexps,Arrays,Funcitons,当然Objects,这些都是对象: JS中,所有值,除了原生值,都是对象:这些原生值包括:strings,numbers('3.14'),true,false,null和undefined 对象是包含变量的变量,js变量可