0
点赞
收藏
分享

微信扫一扫

JavaScript遍历无规律嵌套的多层object,返回带“索引”的map并实现对子属性快速定位

梯梯笔记 2022-04-29 阅读 57
es6前端

目录

前提

举个例子

思路

代码


前提

        在JavaScript中遍历一个长度和深度都不确定的多层嵌套object,是一件难受的事情

        关于object的多层遍历,网上搜到了许多答案,有递归、有循环然后用try catch排错

       object子属性调用,一般用链式

举个例子

        举个数据量大的例子,假设有一百科书,仅目录就有一本书那么厚。这套百科全书采用开放词条,目录会经常变化,层级和长度都不固定。

思路

代码

        生成map与序列表的函数,代码:

//生成map与序列表的函数

function objExpansionMap(obj) {            //obj展平成非嵌套map
    let map = new Map();
    switch (true) {
        case obj === null: case obj === undefined:
            return obj;
        case /string|number|function/.test(typeof obj):
            map.set(0, obj);            //单个值不用拆开
            return map;
    }

    let root = Object.entries(obj);     //根
    let ind = [0];                      //子在何层(深度),第几个(序列)-序列数组
    let tmpInd, tmpChild;
    let parent = root.concat();         //父
    let child, lens, tmpParent;         //子、子键值对中值的长度、暂存父
    let indMap = new Map();             //序列表

    for (let i = 0; i < parent.length; i++) {
        parent != tmpParent && (ind[ind.length - 1] = i);   //判断父更新
        tmpInd = ind.concat();                                //临时ind
        child = getItem(root, ind);                         //找子

        lens = 0; tmpChild = null;

        if (child[1] !== null && child[1] !== undefined) {    //非空
            lens = Object.keys(child[1]).length;
        }

        if (typeof child[1] == "object") {
            if (lens > 0) {                         //子长不为零
                ind.push(0);
                parent = Object.entries(child[1]);  //obj处理成键值对
                i = -1;
            } else if (i < parent.length - 1) {     //子长为0,非末尾
                let broInd = ind.concat();
                broInd[broInd.length - 1] += 1;
                //无弟,跳过,因为空集也会占一个序列,不跳过会出错
                if (getItem(root, broInd) == undefined) { continue; }
            }
        } else {
            tmpChild = child[1];                      //非obj,写入具体值
        }

        if (i == parent.length - 1) {               //末尾
            tmpParent = undefined;
            //找父的弟
            while (tmpParent == undefined && ind.length > 1) {
                ind.pop();
                ind[ind.length - 1] += 1;
                tmpParent = getItem(root, ind);
            }
            //结束判断
            if (tmpParent != undefined || ind.length > 1) {
                parent = tmpParent;                 //更新父
                i = -1;
            }
        }

        let value;
        if (tmpChild === null) {
            value = {
                name: child[0]
            }
        } else {
            value = {
                name: child[0],
                value: tmpChild
            }
        }
        let key = tmpInd.join(",");

        indMap.set(child[0], ()=>{
            return map.get(key);
        });

        map.set(key, value);                        //写入map

    }

    return {
        map: map,
        indMap: indMap
    };                                     //返回map
}

function getItem(item, ind) {               //根据序列数组ind找子
    for (let j = 0; j < ind.length; j++) {
        item = item[ind[j]];                    //找子
        if (j == ind.length - 1) { break; }     //末尾
        item instanceof Array ?                 //将数组默认为键值对,并判断
            item = Object.entries(item[1]) :    //子为数组,返回子之值的键值对
            item = Object.entries(item);        //子非数组,返回自身键值对
    }
    return item;                                //返回子
}

        调用生成map的代码(页面中只需调用一次,除非数据更新),代码:

//map,indMap用来接收函数输出的数据
const {map,indMap} = globalFnWP.objExpansionMap(menus);

        生成map以后,在JavaScript中调用map里的属性,代码:

console.log(map.get("0"));            //根据“索引”调用

console.log(indMap.get("home")());    //根据“名称”调用,名称不能重复

          以下是将要被生成map的object,根据实际需要替换,建议不要嵌套数组:

const menus = {
  home: () => import('@/views/home.vue'),
  effects: {
    jellyRun: () => import('@/views/effects/jellyRun.vue'),
    speadSmooth: () => import('@/views/effects/speadSmooth.vue')
  },
  games: {
    littleGames: {},
    bigGames: {
      Games3D: {
        ballGames: {},
        petGames: {}
      },
      RPG: {},
    }
  },
  tools: {
    counter: () => import('@/views/tools/counter.vue'),
    ryth: () => import('@/views/tools/ryth.vue')
  }
}

        以下是根据上图中的数据输出的后台数据截图:

 

举报

相关推荐

0 条评论