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

前言

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

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));
相关推荐
_一条咸鱼_1 分钟前
Android ARouter 编译器模块深度剖析(二)
android·面试·android jetpack
培根芝士2 分钟前
Electron打包支持多语言
前端·javascript·electron
Baoing_28 分钟前
Next.js项目生成sitemap.xml站点地图
xml·开发语言·javascript
沉默是金~1 小时前
Vue+Notification 自定义消息通知组件 支持数据分页 实时更新
javascript·vue.js·elementui
Pandaconda1 小时前
【新人系列】Golang 入门(十五):类型断言
开发语言·后端·面试·golang·go·断言·类型
在下千玦1 小时前
#去除知乎中“盐选”付费故事
javascript
ohMyGod_1231 小时前
React-useRef
前端·javascript·react.js
每一天,每一步1 小时前
AI语音助手 React 组件使用js-audio-recorder实现,将获取到的语音转成base64发送给后端,后端接口返回文本内容
前端·javascript·react.js
上趣工作室1 小时前
vue3专题1------父组件中更改子组件的属性
前端·javascript·vue.js
getapi1 小时前
flutter app实现分辨率自适应的图片资源加载
前端·javascript·flutter