最近整理之前写过的博客,发现深度拷贝对象的一段代码。想着深度拷贝后我怎么来验证两个对象的值,是否全等呢?
于是乎,我就花点时间写了个深层次多级对象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
}
总结与应用
将多级对象扁平化之后,我们可以做很多事情。
比如下面两个对象a
和b
:
const a = {data:{key:1}}
const b = {data:{key:2}}
a === b // --> false
理论上来说,你如果直接判断他们是不相等的。
但是通过扁平化之后,你再来对他们的Key逐一进行比较,能百分百的确定这两个对象的结构是否一致!
再比如,有MongoDB
开发经验的小伙伴可能会有感触。
在做查询的时候,传递的filter参数
就是完全扁平化的,对于查询效率会大大提升!
还有很多其他的使用场景,就自己去发现和体会了!
本篇文章就说到这里,觉得不错,还请点赞收藏!
励志前端,CSDN唯一账号!关注我,带你了解更多前端知识!