为何未使用变量赋值的JS递归数组切片代码会触发无限循环?
问题原因解答
核心问题根源:全局变量污染
你两段代码中的halfway变量都没有使用var/let/const声明,属于隐式创建的全局变量,所有函数调用共享同一个halfway值,不存在函数级的局部作用域隔离,这是问题的根本原因。
无限循环代码的执行逻辑
触发死循环的核心是参数计算时机晚于第一个递归调用,执行顺序如下:
- 首次调用
half([1,2,3,4,5]),全局halfway被赋值为2,打印数组后,先执行第一个递归调用half(arr.slice(0,2))(也就是half([1,2])) - 进入
half([1,2]),全局halfway被赋值为1,打印数组后,先执行第一个递归调用half(arr.slice(0,1))(也就是half([1])) - 进入
half([1]),第一行就把全局halfway赋值为Math.floor(1/2)=0,因为数组长度等于1,不进入递归直接返回 - 回到
half([1,2])的第二个递归调用,此时需要计算arr.slice(halfway),但全局halfway已经被改成了0,所以arr.slice(0)得到的还是[1,2],相当于又调用了一次half([1,2]),就此进入无限循环。
第二段代码正常运行的原因
第二段代码的差异是提前计算好了两个递归参数并保存,不会被后续的递归调用修改:
- 进入
half([1,2])时,全局halfway被赋值为1,第一时间计算了a = arr.slice(0,1)、b = arr.slice(1),把两个参数值提前存到了局部变量a和b里 - 后续执行
half(a)的时候,哪怕全局halfway被改成了0,也不会影响已经计算完成的b的值,第二个递归调用直接传入已经算好的b也就是[2],不会重新计算slice,所以递归可以正常终止。
修复方案
只需要把halfway声明为函数局部变量即可,两段代码都会正常运行:
function half(arr) { // 加let声明为局部变量,每次函数调用都有独立的halfway let halfway = Math.floor(arr.length / 2) console.log(arr) if (arr.length > 1) { half(arr.slice(0, halfway)); half(arr.slice(halfway)); } return }
内容的提问来源于stack exchange,提问作者Azeth Nu
相关产品推荐
相关产品推荐

