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

前言

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

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));
相关推荐
kyriewen2 分钟前
我把最常踩的8个CORS跨域报错整理了一遍——第8个去年还不存在
前端·javascript
NeilCarmack4 小时前
Deepseek-harness增加桌面版端序列:第 2 讲 · spawn Electron:当前进程如何“交棒“
前端·javascript·electron
ITmaster07314 小时前
天天 AI Coding 的你,如果出去面试,你的竞争力是什么?
人工智能·面试·职场和发展
এ慕ོ冬℘゜7 小时前
使用 jQuery 动态渲染表格与状态切换
前端·javascript·jquery
智购科技自动售货机厂家8 小时前
2026自动售货机AI视觉识别优化:从YOLOv11n模型量化到RKNN部署的端侧推理工程实践~YH
javascript·人工智能·yolo·机器学习·计算机视觉·目标跟踪·perl
晓说前端8 小时前
TypeScript 核心语法应用 —— Vue 3 中的使用(下)
前端·javascript·typescript·类型系统
lancyu11 小时前
# Agent Loop:AI Agent 的唯一直心骨
开发语言·javascript·人工智能
半个落月12 小时前
JavaScript 单例模式详解:从唯一实例到按钮事件
javascript
小的~~13 小时前
面试被问懵了?为什么 Redis 单线程还能保证 Lua 脚本原子性,却偏偏选了 Lua?
redis·面试·lua
weixin_BYSJ198713 小时前
springboot智慧公共交通系统---附源码51123
java·javascript·spring boot·python·django·flask·php