30 lines of code to create a build tree logic with barely reliable performance

I wrote a build tree logic more than half a year ago. Gua Gua Gua. It felt not elegant enough. I felt that I had not considered the details and the code was not streamlined enough. So I wrote it myself again. The overall idea is actually similar, but I have made some optimizations for the details. , the optimization process also allowed me to further understand reference type data, and also made me discover something I had not noticed about the forEach method: when using forEach to loop through the array, you delete an element of the array, and forEach does not It does not help you move the index of the loop process forward by one position, that is, making an i– process, which will cause the entire loop process to lose some elements, so I use a for loop to manually i–. Because this is what I think here: an element can only have one parent element, so when I loop through the entire array, deleting the elements that have found the parent node will make the entire recursive process faster. The overall idea is to find The first-level node, then recursively finds the child nodes of the first-level node, then recursively finds the child nodes of the child node, and then recursively.

function hasParentNode(data, item) {
    
     // 是否存在父节点
  const index = data.findIndex(c => c.id === item.parentId)
  if (~index) return true
}

function getChildrenNodes(parentNodes, allNodes) {
    
     // 获取每一个节点的子节点
  if (parentNodes.length === 0) return
  const node = parentNodes.shift()
  /* allNodes.forEach((item, index) => { // 这里本来是原本的想法,函数式forEach比for循环更优雅
    if (node.id === item.parentId) {
      if (node.children) node.children.push(item)
      else node.children = [item]
      parentNodes.push(item)
      allNodes.splice(index, 1)
    }
  }) */
  for (let i = 0; i < allNodes.length; i += 1) {
    const current = allNodes[i]
    if (node.id === current.parentId) {
      if (node.children) node.children.push(current)
      else node.children = [current]
      parentNodes.push(current)
      allNodes.splice(i, 1) // 删除已经找到父节点的元素
      i -= 1 // 删除元素后把索引往前挪一位
    }
  }
  getChildrenNodes(parentNodes, allNodes)
}

function buildTree(data) {
    
    
  const parentNodes = []; // 有子节点的父级节点数组
  data.forEach((item) => {
    if (!hasParentNode(data, item)) parentNodes.push(item)
  })
  if (parentNodes.length <= 0) return
  const dataSource = [...parentNodes] // 最终数组,引用类型的缘故,你操作parentNodes的每一个元素的过程就是操作dataSource的每一个元素的过程,我经常利用这个特性,如果你不想这样,你可能需要深拷贝复制一个新数组,有时候妙用这一特性能给你带来很多的便利
  getChildrenNodes(parentNodes, data)
  return dataSource
}

practical testing

const source = [
  {
    id: 1,
    parentId: undefined,
    groupName: {
      name: '经理1',
      count: 10
    },
  },
  {
    id: 2,
    parentId: null,
    groupName: {
      name: '经理2',
      count: 1
    },
  },
  {
    id: 3,
    parentId: 0,
    groupName: {
      name: '经理3',
      count: 2
    },
  },
  {
    id: 4,
    parentId: 1,
    groupName: {
      name: '主管1',
      count: 4
    },
  },
  {
    id: 5,
    parentId: 1,
    groupName: {
      name: '主管2',
      count: 6
    },
  },
  {
    id: 6,
    parentId: 4,
    groupName: {
      name: '小组1',
      count: 4
    },
  },
  {
    id: 7,
    parentId: 5,
    groupName: {
      name: '小组2',
      count: 4
    },
  },
  {
    id: 8,
    parentId: 2,
    groupName: {
      name: '主管1',
      count: 0
    },
  },
  {
    id: 9,
    parentId: 3,
    groupName: {
      name: '主管1',
      count: 0
    },
  },
];
console.log(buildTree(source))

In fact, many objects returned by native functions share memory addresses with the original objects, such as find, map, etc. You can understand the concept of stack to help you understand more clearly the return values ​​​​of some js native functions, such as strings. The replace function definitely returns a new character instead of modifying the original string. That’s it for the knowledge point. Ask yourself questions to find out why is the correct way to learn.

let a = [{id: 1, name: 'lane'},{id: 2, name: 'lc'}]
let element = a.find((item) => item.id === 2)
element.name = '数据改变了,引用没有变'
console.log(a)

Guess you like

Origin blog.csdn.net/luo1055120207/article/details/79219789