拷打笔记:对象升维与降维

前言

在我们日常开发的时候对于对象的升维和降维不太常见,但是在我们面试的时候,这两玩意可是常客,接下来主包就给大家讲解一下前些时间被拷打的这两个操作。

1. 对象降维(扁平化)

看到扁平化想必大家都不陌生,在数组中的扁平化操作我们非常常见,接下来我们先来看一下对象的扁平化是什么样子 的:

简单来说呢就是让一个多维的对象变成一个一维的对象,这个一维对象中的key只有一层,并且每个key对应的是原来对象中的值,在了解完了什么是扁平化之后,我们接下来实现一下对对象扁平化的一个操作。

思路:

  1. 先创建一个新对象,然后对原对象进行遍历
  2. 如果key对应的value是原始类型则直接赋值给新对象
  3. 如果不是原始类型,则对其使用一个函数help进行一个递归的操作来获取到key对应的value
  4. 返回生成的新对象

首先我们先定义一个flatObj(target)函数,这个函数里面的主要部分为下面一段代码:

js 复制代码
function flatObj(target) {
  let res = {} 
  function help(target, oldKey) {} // 辅助遍历整个对象
  help(target, '')
  return res
}

在上面的这个函数中,我们在内部定义了一个help函数,这个函数接收两个参数,第一个是我们要拿来扁平化的对象,第二个参数是我们扁平化之后对象中的key。而这个函数的核心功能就在help这个函数中,接下来我们来实现一下这个函数的功能,它的功能主要有以下几点:

  • 遍历传入的target
  • 我们需要凑出来一个新的key用来存值
  • 判断target[key]是不是引用类型,如果是的话就再次调用help进行递归,否则就直接赋值即可

接下来我们来看完整代码:

js 复制代码
const foo2 = {
  "A": 1,
  "B": {
    "A": 2,
    "B": 4
  },
  "CC": {
    "D": {
      "E": 3,
      "F": 5
    }
  }
}

function flatObj(target) {
  let res = {}
  function help(target, oldKey) {
    for (let key in target) {
      // 凑出来新的key
      let newKey
      if (oldKey) {
        if (Array.isArray(target)) {
          newKey = `${oldKey}[${key}]`
        } else {
          newKey = `${oldKey}.${key}`
        }
      } else {
        newKey = key
      }

      // 判断这个value是不是引用类型,不是就直接赋值  
      if (Object.prototype.toString.call(target[key]) === '[object Object]' || Array.isArray(target[key])) {
        help(target[key], newKey)
      } else {
        res[newKey] = target[key]
      }
    }
  }

  help(target, '')
  return res
}

console.log(flatObj(foo2));

2. 对象升维

在看完了对象的扁平化之后,相信对象的升维大家也不难理解,就是把一维对象转换为多维的。接下来我跟大家讲解一下大致思路:

  • 先创建一个新对象
  • 对原对象进行遍历,如果key当中没有'.'则代表是原始类型则直接赋值给新对象
  • 如果value当中有'.'那么就代表升维后对象的该值是引用类型,需要额外的处理
  • 返回得到的新对象
js 复制代码
function fn(obj) {
  let res = {}
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (key.indexOf('.') === -1) res[key] = obj[key]
      else {
        const list = key.split('.') // 获取生成新对象的key列表
        const val = obj[key] // 储存对应的value
        
        // 如果之前没有赋值的话,就创建一个新的对象,否则就用老的对象防止被覆盖
        if (!res[list[0]]) { 
          res[list[0]] = {}
        }
        res[list[0]] = help(res[list[0]], val, list, 1)
      }
    }
  }
  return res
}

接下来我们来看一看其中help函数的思路:

  • 首先我们会传入四个参数,分别是:当前的对象,最后对应的value,key的列表,当前在哪一层对象中
  • 接着我们在执行时先判断是不是到最后一层了,是的话直接返回val即可
  • 如果没到达最后一层,我们就判断当前key位置它是否已经有值,没有的话就创造一个新对象给他,否则我们就在原来的基础上添加即可

tips:我们得防止引用丢失

js 复制代码
const foo1 = {
  'A': 1,
  'B.A': 2,
  'B.B': 4,
  'CC.D.E': 3,
  'CC.D.F': 5
}

function help(obj, val, list, index) {
  if (index === list.length) return val
  // 防止值被覆盖
  if (!obj[list[index]]) {
    obj[list[index]] = {};
  }
  obj[list[index]] = help(obj[list[index]], val, list, index + 1)
  return obj
}

function fn(obj) {
  let res = {}
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (key.indexOf('.') === -1) res[key] = obj[key]
      else {
        const list = key.split('.')
        const val = obj[key]
        if (!res[list[0]]) {
          res[list[0]] = {}
        }
        res[list[0]] = help(res[list[0]], val, list, 1)
      }
    }
  }
  return res
}

console.log(fn(foo1));
相关推荐
不爱说话郭德纲4 分钟前
面试官:你给我讲讲async/await
前端·深度学习·面试
前端小巷子6 分钟前
Promise 链式调用:让异步编程更优雅
前端·面试·promise
有梦想的攻城狮12 分钟前
从0开始学vue:pnpm怎么安装
前端·javascript·vue.js
疯狂的沙粒30 分钟前
uni-app 如何实现选择和上传非图像、视频文件?
前端·javascript·uni-app
·云扬·1 小时前
【PmHub面试篇】性能监控与分布式追踪利器Skywalking面试专题分析
分布式·面试·skywalking
Mintopia1 小时前
光影魔术师的秘密:用 JavaScript 打造软阴影的奇幻世界
前端·javascript·计算机图形学
Mintopia2 小时前
Three.js 粒子系统:让代码化身奇幻造梦师
前端·javascript·three.js
七七&5562 小时前
java面试-场景题
java·python·面试
mpr0xy2 小时前
React Router 中 navigate 后浏览器返回按钮不起作用的问题记录
javascript·react.js·浏览器·路由
itwlz2 小时前
vite配置@别名,以及如何让IDE智能提示路经
开发语言·前端·javascript