JS进阶反对象扁平化

221 阅读2分钟

对象扁平化处理传送门

看我这一篇 juejin.cn/post/721586…

反对象扁平化

实现一个函数 unflatten,将以下扁平化后的对象还原为 output 对象

var input = {
    "a": 1,
    "b[0]": 1,
    "b[1]": 2,
    "b[2].c": true,
    "b[3][0]": 3,
    "d.e": 2,
    "d.f.e.g": 3,
    "e.j": 222,
    "e.k[0]": 1,
    "e.k[1]": 2,
    "e.k[2]": 3,
    "e.k[3].d": 32,
    "josie": "so cool"
}

var output = {
  a: 1,
  b: [ 1, 2, { c: true }, [ 3 ] ],
  d: { e: 2, f: 3 },
  g: null, 
  e: {j: 222, k: [1,2,3,{a: null, d:32}]},
  f: undefined,
  h: '',
  josie: 'so cool'
}

解题思路

  1. 将input对象遍历拿到所有key值存储在一个数组中flattenKeyArr
  2. 遍历flattenKeyArr,对每一项key进行反扁平化还原
  3. 根据/\.?([^.\[\]]+)$|\[(\d+)\]$/正则规则匹配出包含.或[]的key值字符串,再通过slice截取出真正的key
  4. 根据拿到的这一层级的key,去从data中获取value a. 如果没有的话,说明当前key值存在子节点,那么需要将其push到flattenKeyArr中,继续遍历查找。 b. 如果找到value的话,就将其赋值给target
  5. 每一轮循环后,target都会存入当前这个key的值(说实话这里的写法有点不太好理解,我理解为绑定引用,这样target和result就绑定了,看明白的同学可以评论区点评下)

代码

参考网上某大佬写的,稍微改了一点点

const unflatten = (data) => {
  // 非基础类型return
  if (Object(data) !== data || Array.isArray(data)) {
      return data;
  }
  const regex = /\.?([^.\[\]]+)$|\[(\d+)\]$/;
  const flattenKeyArr = Object.keys(data);
  let result, p;

  while ((p = flattenKeyArr.shift())) { // 循环一遍取出一个,改变原数组
    const match = regex.exec(p);
    // match[2]的值意为具体取到[]里面的数字,数组类型取[2],对象类型取[1]
    const arrayItem = match[2]
    const objItem = match[1]
    const newData = arrayItem ? [] : {};
    let target;
    // 存在子节点(因为 .[ 不会在第一个,所有可以这么判断)
    if (match.index) {
      // 截取出匹配过的key值
      const key = p.slice(0, match.index);
      // data中不存在这个key,说明还有子节点
      if (!(key in data)) {
        // 赋值空类型,方便后面添加属性
        data[key] = newData;
        flattenKeyArr.push(key);
      }
      // 绑定引用
      target = data[key];
    } else {
      if (!result) {
        result = newData;
      }
      // 绑定引用,秒啊
      target = result
    }
    // 每轮循环都要赋值
    target[arrayItem || objItem] = data[p];
  }
  return result;
};