如何将下面的递归函数转换为纯函数

How to turn the following recursive function into a pure function?

本文关键字:转换 函数 递归函数      更新时间:2023-09-26

以下函数将对象附加到嵌套数组中(通过递归搜索):

function appendDeep (arr, obj, newObj) {
  if (arr.indexOf(obj) !== -1) {
    arr.splice(arr.indexOf(obj) + 1, 0, newObj)
  } else {
    arr.map(item => {
      if (item.children) spliceDeep(item.children, obj)
    })
  }
}

示例:

const colors = {
  children: [
    {
      name: 'white',
    },
    {
      name: 'yellow',
      children: [
        {
          name: 'black'
        }
      ]
    }
  ]
}
const color = {
  name: 'black'
}
const newColor = {
  name: 'brown'
}
appendDeep(colors.children, color, newColor)

结果:

children: [
     [
       {
         name: 'white',
       },
       {
         name: 'yellow',
         children: [
           {
             name: 'black'
           },
           {
             name: 'brown'
           }
         ]
       }
     ]
   ]

正如您所看到的,appendDeep返回一个副作用;它修改CCD_ 2。所以我决定返回数组(这样函数就会变得纯粹):

function findDeep (arr, obj) {
  if (arr.indexOf(obj) !== -1) {
    console.log(arr)
    return arr
  } else {
    arr.map(item => {
      if (item.children) findDeep(item.children, obj)
    })
  }
}

并使用这样的新功能:

const newArr = findDeep(colors.children, color)
newArr.splice(newArr.indexOf(color) + 1, 0, newColor)

但我得到了这个错误:

bundle.js:19893 Uncaught TypeError: Cannot read property 'splice' of undefined

我做错了什么?

(注意:这是CodePen。)

(注意2:console.log(arr)确实返回嵌套的子级。但由于某种原因,它们在函数之外变成了undefined。)

您不会在map中返回递归findDeep方法。返回该值以使递归工作,因为您的条件分支没有从映射中返回任何内容。因此,您得到的结果是undefined。JSBin

首先,一个find方法,它将返回请求项所在的数组(作为直接子项)。

function findDeep(arr, obj) {
    return arr.map((item) => {
        if (item.name === obj.name) {
            return arr;
        } else if (item.children) {
            return findDeep(item.children, obj);
        } else {
            return undefined;
        }
    }).reduce((prev, cur) => {
        return prev ? prev : cur;
    });
}

您可以使用它将项目附加到列表中,但这仍然会修改原始数组:

function appendDeep(arr, color, newColor) {
    let found = findDeep(arr, color);
    if (found) {
        found.splice(found.indexOf(color) + 1, 0, newColor);
    }
    return arr;
}

如果您不想修改原始数组,事情会变得更加复杂。这是因为pushsplice等标准数组函数将修改原始数组。没有快速的解决方案,至少我不知道,因为最好你不想克隆比你真正需要的更多的项目。

您不需要克隆black,但需要克隆包含它的阵列(它可以简单地重用黑色的现有对象。)这意味着黄色的对象也需要克隆(使用克隆的阵列),黄色所在的阵列也需要克隆。但是,同一阵列中的白色不会被修改,也不需要克隆。我还没想好该怎么做。

这是一个使用Array#somethisArgs的提案。

function appendDeep(object, search, insert) {
    function iter(a) {
        if (a.name === search.name) {
            this.children.push(insert);
            return true;
        }
        return Array.isArray(a.children) && a.children.some(iter, a);
    }
    object.children.some(iter, object);
}
var colors = { children: [{ name: 'white', }, { name: 'yellow', children: [{ name: 'black' }] }] },
    color = { name: 'black' },
    newColor = { name: 'brown' };
appendDeep(colors, color, newColor);
document.write('<pre>' + JSON.stringify(colors, 0, 4) + '</pre>');