自定义_reduce函数调用后原数组未修改?预期结果不符求解
为什么原数组未被修改?
先看你提供的代码和运行结果:
相关代码
遍历函数_each
function _each(list, iter){ for(var i=0; i<list.length; i++){ iter(list[i]); } }
类数组兼容的_rest函数
var slice = Array.prototype.slice; function _rest(list, num){ return slice.call(list, num || 1); }
自定义_reduce函数
function _reduce(list, iter, memo){ if(arguments.length == 2){ memo = list[0]; list = _rest(list); } _each(list, function(val){ memo = iter(val, memo); }) return memo; }
调用代码
var arr = [1, 2, 3, 4]; console.log(_reduce(arr, function(a, b){return a + b})); console.log(arr);
实际输出
10 (4) [1, 2, 3, 4]
你预期原数组会变成[2,3,4]但没实现,核心原因有两点:
核心原因
_rest返回的是新数组而非修改原数组slice.call(list, num || 1)调用的是数组的slice方法,这个方法的特性是不修改原数组,而是返回一个包含原数组从指定索引开始的所有元素的新数组。所以_rest并没有动过原数组的内容。函数内部的
list变量是局部引用
当你把arr传入_reduce时,函数内部的list变量拿到的是原数组引用的副本。执行list = _rest(list)只是把这个局部变量的指向换成了_rest返回的新数组,完全不会影响外部的arr变量——它依然指向最初的那个数组。
说白了,你只是在函数内部换了个局部变量的指向,根本没碰原数组的内容,所以原数组自然不会有变化。
如果非要修改原数组(不推荐,会产生副作用),可以直接操作原数组,比如用shift()方法:
function _reduce(list, iter, memo){ if(arguments.length == 2){ memo = list[0]; list.shift(); // 直接移除原数组的第一个元素 } _each(list, function(val){ memo = iter(val, memo); }) return memo; }
但实际开发中,更推荐保持原数组不变的写法,也就是你最初的实现,这样的代码更符合函数式编程的无副作用原则,避免意外的bug。
内容的提问来源于stack exchange,提问作者이규빈
相关产品推荐
相关产品推荐

