递归是函数调用自身,而函数又是可复用的代码封装。
那么递归必然每次都是进行相同的处理逻辑。
递归会使原先的大问题变小,变小后的问题还用“相同的逻辑”来处理。
说到“相同的逻辑”,不由得让人会想到数组和对象。
因为数组中的元素可以是数组,
对象中的属性值也可以是对象。
那么对嵌套的数组和嵌套的对象的遍历,必然需要使用递归。
1.遍历嵌套数组
function visit(array,fn){ if(Array.isArray(array)){ return array.forEach(function(v){ visit(v,fn); }) }else{ fn(array); } } var array = [1,2,[3,4],[5,[6,7]]]; visit(array,function(v){ //输出数组的成员 console.log(v); //1,2,3,4,5,6,7 }) var result = []; visit(array,function(v){ v%2 == 0 && result.push(v); }) console.log(result);// 2 4 6
其实,此时真正需求是:
如果能把嵌套数组“展平”变成一维数组,那岂不是想用什么API,就用什么了。
展平函数也需要使用递归:
1 function flatten(array, result) { 2 !result && (result = []); 3 for (var i = 0; i < array.length; i++) { 4 if (Array.isArray(array[i])) { 5 flatten(array[i], result); 6 } else { 7 result.push(array[i]); 8 } 9 } 10 return result; 11 } 12 var array = [1, 2, [3, 4], [5, [6, 7]]]; 13 console.log( flatten(array) ); //输出: [1, 2, 3, 4, 5, 6, 7]
2.嵌套对象的遍历
对象的深拷贝就是其中应用之一。
3.对象的值相等比较操作。
function equal(a, b) { // 三等,自然值就相等 if (a === b) return true; // 要求类型一致 var className = {}.toString.call(a); if (className !== {}.toString.call(b)) return false; // 如果是数组 if (Array.isArray(a)) { var length = a.length; if (length !== b.length) return false; while(length--) { if (!equal(a[length], b[length])) return false; } } else if (typeof a == 'object'){ // 如果是对象 var keys = Object.keys(a); var length = keys.length; if (length != Object.keys(b).length) return false; while(length--) { var key = keys[length]; if (!(key in b) || !equal(a[key], b[key])) return false; } } else { // 基本类型 return a == b; } return true; } console.log( equal(1, 1) ); console.log( equal([1, 2], [1, 2]) ); var a = [1, 2, [3, 4], [5, [6, 7]]]; var b = [1, 2, [3, 4], [5, [6, 7]]]; console.log( equal(a, b) ); var c = { x : [1, 2, 3], y : { z: { w: 1}}, t: 2}; var d = { x : [1, 2, 3], y : { z: { w: 1}}, t: 2}; console.log( equal(c, d) );
输出结果: