JavaScript嵌套调用带剩余参数函数时首个参数未被处理问题
问题说明
编写了一个可变参数函数,预期功能为遍历所有传入参数,为每个参数拼接字符串"Transformed",原实现代码如下:
function Transform(...children) { return children.map(child=> child + " Transformed") } document.write( Transform( Transform(" test1", " test2"), // 仅test2被双次转换 Transform(" test3") // 此处单参数可正常被双次转换 ) )
实际运行存在异常:嵌套调用该函数时,单次调用仅传入1个参数时运行结果符合预期,单次传入多个参数时第一个参数不会被正确处理。当前运行结果中test1末尾没有拼接两个"Transformed",但test2、test3均正常拼接了两个"Transformed",需要修改函数实现所有传入参数都能正确在末尾拼接"Transformed"的效果。
问题根因
异常来自函数返回值类型和JS的隐式类型转换规则:
Transform函数执行后返回的是数组,多参数调用时返回包含多个字符串元素的数组。当这个数组作为参数传入外层Transform时,map会把整个数组当成单个遍历项处理。数组和字符串做加法运算时会自动调用toString(),将数组元素用逗号拼接成字符串,最终导致内层多参数返回的数组被整体当成一个字符串拼接,出现第一个元素仅拼接一次、最后一个元素拼接两次的错位。- 单参数调用时返回长度为1的数组,转字符串时没有逗号分隔,刚好符合双次拼接的预期,属于巧合。
修复方案
在遍历拼接前,先把嵌套传入的数组拍平,让所有层级的字符串参数都被单独遍历处理即可。
ES6+ 环境下可以直接用Array.prototype.flat实现,代码如下:
function Transform(...children) { // Infinity参数表示拍平所有层级的嵌套数组 return children.flat(Infinity).map(child => child + " Transformed") } document.write( Transform( Transform(" test1", " test2"), Transform(" test3") ) )
上述代码执行后,所有参数不管嵌套多少层、单次调用传多少个参数,都会按嵌套层级正确拼接对应次数的Transformed。如果需要直接输出无逗号分隔的拼接结果,可以在map后调用join('')把数组转成连续字符串即可。
如果需要兼容不支持flat方法的老旧运行环境,可以用递归实现数组拍平,代码如下:
function flatten(arr) { return arr.reduce((prev, curr) => { return prev.concat(Array.isArray(curr) ? flatten(curr) : curr) }, []) } function Transform(...children) { return flatten(children).map(child => child + " Transformed") }
内容的提问来源于stack exchange,提问作者math
相关产品推荐
相关产品推荐

