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

前言

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

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));
相关推荐
JieE2124 小时前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
candyTong7 小时前
RTK 技术原理:一次典型会话里,80% 上下文是怎么省下来的
javascript·后端·架构
_柳青杨11 小时前
深入理解 JavaScript 事件循环
前端·javascript
JustHappy14 小时前
我汇总了身边朋友的经历才发现,其实第一份实习是最难找的......
前端·后端·面试
uhakadotcom14 小时前
在python 的 工程化架构中 ,什么是 薄包装器层?
后端·面试·github
大家的林语冰17 小时前
ES5 凉凉,Babel 8 正式发布,默认不再编译为 ES5 和 CJS......
前端·javascript·前端工程化
假如让我当三天老蒯18 小时前
模块化:ES Module 与 CommonJS 的区别
前端·面试
沉默王二18 小时前
面试官:RAG 不用向量数据库,用 MySQL 硬扛?我:100 万向量不是很轻松?
mysql·面试·ai编程
weedsfly19 小时前
异步编程全景与事件循环——彻底搞懂 JS 执行机制
前端·javascript