这是之前字节面试时的一道题,当时脑子比较混乱,但在面试官指引下还是写出了大部分,后面又仔细想了想,感觉还是得多写题。我们来看看吧

题目

  1. const entry = [{
  2. id: '1',
  3. isOpen: true
  4. }, {
  5. id: '2',
  6. children: [{
  7. id: '21',
  8. children: [{
  9. id: '211',
  10. isOpen: false
  11. }, {
  12. id: '212',
  13. isOpen: false
  14. }]
  15. }]
  16. }, {
  17. id: '3',
  18. isOpen: false
  19. }]
  20. // 平铺,如果有isOpen属性则直接输出,如果没有则查看children里面有没有
  21. // 只要children里面有一个true,那么外层就是true
  22. let output = {'1':true, '2':true, '21':true, '211':true, '212':false, '3':false}

思路:

(1)首先是先遍历这个树状数组的每一层,拿到 id 当 key,如果有 isOpen 属性,则直接把 isOpen 属性赋给 key,如果没有 则先 递归得到 children的遍历结果,并用 Object.assign合并res和递归的结果

没有isOpen属性的则被跳过了,因此我们把没有isOpen属性的单独考虑
image.png

(2)做到这里,有 isOpen 属性已经得到了 ,但是没有 isOpen 属性的我们则需要另外考虑,我的思路就是另外写一个judge函数来递归判断 其 children 内有没有 isOpen 是 等于 true的

  1. function flatObj(arr) {
  2. let res = {}
  3. for (const item of arr) {
  4. let id = item.id
  5. let isOpen = item.isOpen
  6. if (isOpen !== undefined) {
  7. res[id] = isOpen
  8. } else {
  9. // 没有isOpen则查找children,并且合并递归结果
  10. Object.assign(res, flatObj(item.children))
  11. // 没有isOpen单独考虑
  12. res[id] = judge(item.children)
  13. }
  14. // 分步打印看结果
  15. console.log(res);
  16. }
  17. return res
  18. }
  19. // 判断children内是否有isOpen=true
  20. function judge(arr){
  21. let flag = false
  22. for (const item of arr) {
  23. let isOpen = item.isOpen
  24. if (isOpen !== undefined) {
  25. if(isOpen){
  26. flag = true
  27. }
  28. } else {
  29. // 如果还是没有,则继续去children内找,最后都没有则返回false
  30. flag = judge(item.children)
  31. }
  32. }
  33. return flag
  34. }
  35. console.log(flatObj(entry));

最后我们来看指向结果,由于直接看结果不明显,因此我们把它分步打印出来
image.png
由结果我们可以看出,3是被最后才加进去的,由于对象内部的key排列问题,3被排到了前面,但这不影响结果。