Bootstrap

JS深层次多级对象Key的遍历方法,将多层级对象扁平化


最近整理之前写过的博客,发现深度拷贝对象的一段代码。想着深度拷贝后我怎么来验证两个对象的值,是否全等呢?

于是乎,我就花点时间写了个深层次多级对象Key的遍历方法。

一、深层次多级对象介绍

我们都知道在JavaScript中,定义一个对象很简单,如:

var obj1 = {a:1,b:'简单对象',c:function(){return 3;}}

但是,当这个对象中的元素又加入了引用类型,这个对象就变成了多级对象了,如:

var obj2 = {a:[1,2,3],b:'多级对象',c:function(){return 3;}}

加上对象的嵌套之后,一个JavaScript对象可能就像下面这样了:

var obj3 = {
  a:1,
  b:{
    b1:3,
    b2:[
      {
        b21:1,
        b22:{
          b221:2,
          b222:[1,2,3],
          b223:function(){ console.log('b223') }
        }
      },
      22,
      function(){console.log('b23')}
    ]
  },
  c:[1,2,3]
}

看见这中数据对象,是不是觉得很恶心…我也有点恶心

问题提出:

对于简单的对象使用for..in或者Object.keys就可以遍历其中的key了,但是对于这种又是数组又是对象的多级对象,怎么办呢?

二、深层次多级对象Key的遍历方法实现

难也不难,下面直接给出代码,熟练运用递归,判断一下引用类型,就行了!

不要被下面这段代码唬住了,真的不难!每个方法及关键步骤,我都为你写好了注释!

    /**
     * 遍历key
     * @param {array|object} arrOrObj 待遍历的对象
     * @param {(key,element)=>void} cb 遍历的函数
     * @param {string} rootKey 根节点
     */
    function itorKey(arrOrObj,cb,rootKey=''){
        // 辅助函数 判断是否object
        function isObj(str) {
            return typeof(str) === "object";
        }

        // 辅助函数 判断是否array
        function isArr(str){
            return Object.prototype.toString.call(str) === '[object Array]'
        }

        // 数组的核心逻辑
        if (isArr(arrOrObj)) {
            arrOrObj.map(function(ele,index){
                // 新的rootKey
                const newRootKey = rootKey+'['+index+']'
                cb(newRootKey,ele)
                // 递归遍历
                itorKey(ele,cb,newRootKey)
            })
            return;
        }
        // 对象的核心逻辑
        if(isObj(arrOrObj)){
            for (const key in arrOrObj) {
                if (Object.hasOwnProperty.call(arrOrObj, key)) {
                    const element = arrOrObj[key];

                    // 新的rootKey
                    const newRootKey = rootKey+'.'+key
                    cb(newRootKey,element)
                    // 递归遍历
                    itorKey(element,cb,rootKey+'.'+key)
                }
            }
            return;
        }
    }

三、验证一下我们的遍历函数

itorKey(obj3,function(key,ele){
  // 直接打印
  console.log(key,'==>',ele)
},'')

结果如下:

.a ==> 1
.b ==> {b1: 3, b2: Array(3)}
.b.b1 ==> 3
.b.b2 ==> (3) [{…}, 22, ƒ]
.b.b2[0] ==> {b21: 1, b22: {…}}
.b.b2[0].b21 ==> 1
.b.b2[0].b22 ==> {b221: 2, b222: Array(3), b223: ƒ}
.b.b2[0].b22.b221 ==> 2
.b.b2[0].b22.b222 ==> (3) [1, 2, 3]
.b.b2[0].b22.b222[0] ==> 1
.b.b2[0].b22.b222[1] ==> 2
.b.b2[0].b22.b222[2] ==> 3
.b.b2[0].b22.b223 ==> ƒ (){ console.log('b223') }
.b.b2[1] ==> 22
.b.b2[2] ==> ƒ (){console.log('b23')}
.c ==> (3) [1, 2, 3]
.c[0] ==> 1
.c[1] ==> 2
.c[2] ==> 3
itorKey(obj1,function(key,ele){
  // 直接打印
  console.log(key,'==>',ele)
},'')

结果如下:

.a ==> 1
.b ==> 简单对象
.c ==> ƒ (){return 3;}

除了遍历之外,itorKey方法还对遍历的key做了一个优化,可以传递一个rootKey参数,比如:

itorKey(obj1,function(key,ele){
  // 直接打印
  console.log(key,'==>',ele)
},'obj1')

结果如下:

obj1.a ==> 1
obj1.b ==> 简单对象
obj1.c ==> ƒ (){return 3;}

四、将多级对象扁平化

有了上面的遍历方法,其实扁平化就很好实现了,这里留个作业给大家吧!

大家可以评论区将多级对象扁平化的函数写出来,发到评论区。

函数的入参:一个多级对象,比如:

const example = {
  a:1,
  b:[2,3,4],
  c:{
    c1:5,
    c2:[6,{c22:7,c23:8},9]
  }
}

函数的出参:一个扁平化的对象,对应example对象的输出应该如下:

{
	".a": 1,
	".b": [2, 3, 4],
	".b[0]": 2,
	".b[1]": 3,
	".b[2]": 4,
	".c": {
		"c1": 5,
		"c2": [6, {
			"c22": 7,
			"c23": 8
		}, 9]
	},
	".c.c1": 5,
	".c.c2": [6, {
		"c22": 7,
		"c23": 8
	}, 9],
	".c.c2[0]": 6,
	".c.c2[1]": {
		"c22": 7,
		"c23": 8
	},
	".c.c2[1].c22": 7,
	".c.c2[1].c23": 8,
	".c.c2[2]": 9
}

总结与应用

将多级对象扁平化之后,我们可以做很多事情。

比如下面两个对象ab

const a = {data:{key:1}}
const b = {data:{key:2}}

a === b  // --> false

理论上来说,你如果直接判断他们是不相等的。

但是通过扁平化之后,你再来对他们的Key逐一进行比较,能百分百的确定这两个对象的结构是否一致!

再比如,有MongoDB开发经验的小伙伴可能会有感触。

在做查询的时候,传递的filter参数就是完全扁平化的,对于查询效率会大大提升!

还有很多其他的使用场景,就自己去发现和体会了!

本篇文章就说到这里,觉得不错,还请点赞收藏!
励志前端,CSDN唯一账号!关注我,带你了解更多前端知识!

;