JavaScript Array、Object、数组树形结构转换、对象等数据转换及处理总结

JS 对象转数组

  • Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for…in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。
  • Array.prototype.map 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。
    假如说我们有一个城市的数据,这个数据记录了城市的某种值,后端一般就返回一个简单的数据格式,如:
let cityObj = {
    shenzhen: 31,
    guangzhou: 29
}

如果我们需要用在饼图统计图上,就需要把这个 cityObj 改成数组格式 cityArr,如

let cityArr = [
  {cityName: 'shenzhen', value: 31},
  {cityName: 'guangzhou', value: 29}
]

如果属性少的话,你可以用 . 的方式手动取值赋值改成数组格式,如:

let cityArr = [
  {cityName: 'shenzhen', value: cityObj.shenzhen},
  {cityName: 'guangzhou', value: cityObj.guangzhou}
]

但是如果城市非常多,甚至是整个中国所有的城市,那你用 . 取值赋值的方式就会显得很麻瓜,所以这里建议用遍历的方式,或者你也可以对这个东西封装加入自己的工具函数也很好。

下面例举两种方式去完成这个对象转数组。

使用 Object.entries + Array.prototype.map 对象转数组

let cityObj = { // 对象数据
  shenzhen: 31,
  guangzhou: 29
}
// 封装
function objToArr(data, typeName, valueName) {
  // Object.entries(data) 先把数据转成 [[key, value], ...]
  // .map(([typeName, valueName]) => ({typeName, valueName})) 对 [key, value] 解构
  // 然后返回 {typeName: typeName, valueName: valueName} 格式

  return Object.entries(data).map(([typeName, valueName]) => ({typeName, valueName}))
}

// 执行
objToArr(cityObj, 'cityName', 'value')

使用 Object.keys + Array.prototype.map 对象转数组

let cityObj = { // 对象数据
  shenzhen: 31,
  guangzhou: 29
}

// 封装
function objToArr(data, typeName, valueName) {
  // Object.keys(data) 先把数据转成 [key, key, key, ...]
  // .map(key => ({typeName: key, valueName: data[key]})) 
  // 遍历 keys 取出 key 和 value data[key],
  // 然后返回 {typeName: typeName, valueName: valueName} 格式

  return Object.keys(data).map(key => ({typeName: key, valueName: data[key]}))
}

objToArr(cityObj, 'cityName', 'value')

JS 数组转对象

  • Object.fromEntries 方法把键值对列表转换为一个对象。
  • Array.prototype.map 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。

如果我们需要将在饼图统计图上的数据 cityArr 传给后端,一般来说都会简化数据,简化成 cityObj,如:

let cityArr = [
  {cityName: 'shenzhen', value: 31},
  {cityName: 'guangzhou', value: 29}
]
let cityObj = {
    shenzhen: 31,
    guangzhou: 29
}

既然有 Object.entries,也有 Object.fromEntries,那可以直接使用 Object.fromEntries + Array.prototype.map 来完成这个格式转化

使用 Object.fromEntries + Array.prototype.map 数组转对象

let cityArr = [ // 数组数据
  { cityName: 'shenzhen', value: 31 },
  { cityName: 'guangzhou', value: 29 }
]

// 封装
function arrToObj(data, typeName, valueName) {
  // data.map(item => ([item.typeName, item.valueName])) 先把数据转成 [[key, value], ...]
  // Object.fromEntries() 相当于 Object.entries() 逆方法
  // 然后返回 {typeName: valueName} 格式

  return Object.fromEntries(data.map(item => ([item[typeName], item[valueName]])))
}

arrToObj(cityArr, 'cityName', 'value')

JS 一维数组转、树形结构数组相互转换

如果有用到权限树或者文件模块,一般都少不了从后端拿回来的数据做一维数组转树形结构,或者传输给后端时需要树形结构转一位数组扁平化,除非你和后端有亲密关系,不然的话这些都是需要前端自己来做处理。

例如,我们需要将 dataArr 转成 dataTree

let dataArr = [
  { id: 1, pid: 0 },
  { id: 2, pid: 1 }
]
let dataTree = [
  {
    id: 1,
    pid: 0,
    children: [
      {
        id: 2,
        pid: 1
        children: []
      }
    ]
  }
]

递归方法转树形结构数据

  • 计算量大
  • 不会改变原有数据
let data = [ // 如果后端跟你没有亲密关系,你拿到的数据就是列表
  { id: 1, pid: 0 },
  { id: 2, pid: 0 },
  { id: 3, pid: 1 },
  { id: 4, pid: 2 },
  { id: 5, pid: 3 },
  { id: 6, pid: 4 },
  { id: 7, pid: 5 },
  { id: 8, pid: 6 },
]

function arrToTreeData(data, pidVal = 0, pidName = 'pid', childName = 'children') {
  // 一般 pid 就是 parentId,指的是父级 id,这里默认是 pid
  // 一般 pidVal 的值为 0 时,默认是根节点
  // childName 在大多数表格,多级嵌套等组件里通常都是用 children 命名,这里默认是 children
  let result = [] // 初始化

  // 递归匹配,计算量较大
  data.forEach(item => {
    if (item[pidName] === pidVal) {
      result.push({
        ...item,
        [childName]: arrToTreeData(data, item.id)
      })
    }
  })

  return result
}

arrToTreeData(data)

对象引用法转树形结构数据

  • 计算量小
  • 不使用深拷贝则会改变原始数据
let data = [ // 如果后端跟你没有亲密关系,你拿到的数据就是列表
  { id: 1, pid: 0 },
  { id: 2, pid: 0 },
  { id: 3, pid: 1 },
  { id: 4, pid: 2 },
  { id: 5, pid: 3 },
  { id: 6, pid: 4 },
  { id: 7, pid: 5 },
  { id: 8, pid: 6 },
]

function arrToTreeData(data, pidName = 'pid', childName = 'children') {
  // 一般 pid 就是 parentId,指的是父级 id,这里默认是 pid
  // childName 在大多数表格,多级嵌套等组件里通常都是用 children 命名,这里默认是 children
  let obj = {} // 初始化
  let result = [] // 初始化

  // 将数据以对象的格式先存起来
  data.forEach(item => {
    obj[item.id] = item
  })

  for (let i = 0; i < data.length; i++) {
    let item = data[i]
    // 这里去 obj 里找,如果没有找到那就是 undefined,说明这个当前 item 是根节点
    let parent = obj[item[pidName]] 
    if (parent) {
      (parent[childName] || (parent[childName] = [])).push(item)
    } else {
      result.push(item)
    }
  }

  return result
}

arrToTreeData(data)

广度法树形结构数据扁平化

  • 不使用深拷贝则会改变原始数据
function cutTree(data, childName = 'children') {
  let result = [];

  while (data.length != 0) {
    let shift = data.shift();
    let children = shift[childName]
    delete shift[childName]
    result.push(shift)

    if (children) {
      children.forEach(item => {
        data.push(item)
      })
    }
  }
  return result
}

欢迎指导交流