小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
上一篇文章讲解了如何实现下列对象扁平化,这篇将讲解如何反扁平化(如何将newobj转化为obj)。
const obj = {
a: 'a',
b: [1,2,{c:[1,2,3,4]},4],
c: { e: 5, f: 6 },
d: undefined,
f:[1,[1,2,[5,6]]]
};
//转换得到如下新数据结构:
const newobj = {
a: 'a',
'b[0]': 1,
'b[1]': 2,
'b[2].c[0]': 1,
'b[2].c[1]': 2,
'b[2].c[2]': 3,
'b[2].c[3]': 4,
'b[3]': 4,
'c.e': 5,
'c.f': 6,
d: undefined,
'f[0]': 1,
'f[1][0]': 1,
'f[1][1]': 2,
'f[1][2][0]': 5,
'f[1][2][1]': 6
}
1、数组转对象
-
首先还是观察我们要转换的对象,它是一个只有一层的对象,我们要做的就是它的将
key值转化为对象结构,比如:c.e转换成c:{e:...},解决了这个问题那么这个功能就实现了50%。 -
那么如何将
c.e转化成对象结构呢?我们先实现一个如何将数组转化成对象:
// 将数组转换成链表结构(ps:链表在js中的表现其实就是一个对象,这里我们不转化链表,直接将数组转化成对象)
const arr = ['a','b','c','d']
// 构造一个转换方法
function transformToLink(arr){
// 构造一个我们需要的目标对象
let head = {}
// 构造一个指针,用来遍历数组切换
let tmp = head
for(let i =0;i<arr.length;i++) {
let cur = arr[i]
//当前数组值得下一个
let next = arr[i+1]
// 当下一个存在的时候,我们就构造一个新的对象赋值,否则我们直接赋值一个undefined
if(next){
let o = {}
tmp[cur] = o
//这里需要移动指针指向,将指针指向下一个对象
tmp = o
}else{
// 没有我们就直接赋值
tmp[cur] = undefined
}
}
return head
}
- 测试一下,没问题:
- 这步我们实现了数组转对象,那么
c.e不是就可以先split分割成数组再转化嘛?
2、上一步我们实现了a.b.c.d.e.f转换成对象,但是还有'b[2].c[0]'、'f[1][2][0]'这类结构的key,接下来我们实现这部分的转化。
- 首先还是先观察数据结构,当
key中包含[]时候说明是个数组对象,我们再构造的时候就不能像上面一下构造对象而是构造数组,下面,我们将上面的方法修改一下:
//转化key eg:key = b[2][0].c[0]
function transformkey(key){
const arr = key.split('.')
let head = {}
let tmp = head
for(let i =0;i<arr.length;i++) {
let key = arr[i]
let nextKey = arr[i + 1];
//这里需要判断key 是否包含[]字符串,如果是则是数组结构
if(/\[.+?\]/g.test(key)){
//可能是多维数组,匹配数组维度
let indexs = key.match(/\[(.+?)\]/g);
//获取数组的key值
let _key = key.match(/^(.+?)\[/)[1];
//构造一个新数组
let n = []
tmp[_key] = n
//构造完数组对数组里面进行构造
for(let j=0;j<indexs.length;j++){
let index = indexs[j].replace(/\[|\]/g, '');
let nextIndex = indexs[j+1]
//数组包含数组
if(nextIndex){
let o = []
n[index] = o
//如果还包含数组,将n指针指向下一个数组
n = o
}else{
//如果后面还有则构造对象
if (nextKey) {
let o = {}
n[index] = o
tmp = o
} else {
n[index] = undefined
}
}
}
} else {
//不是数组和之前方法保持一致
if (nextKey) {
let o = {}
tmp[key] = o
tmp = o
} else {
tmp[key] = undefined
}
}
}
return head
}
- 测试一下:
- 数据是转化成功的,既然
key-value转换成功,那下面我们对整个对象进行转换,完成代码入下(注意转换是考虑构造新数组或新对象时,需要判断前面是否已经构造过,过这部分我会在代码中表示出来):
function unflatten(obj) {
let o = {}
for (let key in obj) {
transformKey(key, obj[key], o)
}
return o
}
//转化key
function transformKey(key,value,head){
const arr = key.split('.')
let tmp = head
for(let i =0;i<arr.length;i++) {
let key = arr[i]
let nextKey = arr[i + 1];
//这里需要判断key 是否包含[]字符串,如果是则是数组结构
if(/\[.+?\]/g.test(key)){
//可能是多维数组,匹配数组维度
let indexs = key.match(/\[(.+?)\]/g);
//获取数组的key值
let _key = key.match(/^(.+?)\[/)[1];
//构造数组需要判断是否已经存在
tmp[_key] = tmp[_key]?tmp[_key]:[]
let n = tmp[_key]
//构造完数组对数组里面进行构造
for(let j=0;j<indexs.length;j++){
let index = indexs[j].replace(/\[|\]/g, '');
let nextIndex = indexs[j+1]
//数组包含数组
if(nextIndex){
//构造数组需要判断是否已经存在
n[index] = n[index]?n[index]:[]
//如果还包含数组,将n指针指向下一个数组
n = n[index]
}else{
//如果后面还有则构造对象
if (nextKey) {
//构造对象需要判断是否已经存在
n[index] = n[index]?n[index]:{}
tmp = n[index]
} else {
n[index] = value
}
}
}
} else {
//不是数组和之前方法保持一致
if (nextKey) {
//构造对象需要判断是否已经存在
tmp[key] = tmp[key]?tmp[key]:{}
tmp = tmp[key]
} else {
tmp[key] = value
}
}
}
return head
}
- 测试结果: