JavaScript 递归的几种写法

Posted 笑虾

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript 递归的几种写法相关的知识,希望对你有一定的参考价值。

文章目录

匿名函数实现递归

知识点 arguments.callee 对于arguments大家应该都认识吧。callee就是函数自身
官方建议用命名函数实现递归。(也就是叫你调用函数名)

[
	
		id: 1,
		children: [...]
	,
	
		id: 2,
		children: [...]
	
]
	// 把一个树展平。
	function recursion(arr)
		var flatObj = ;
		
		(function(arr)
			
			for(var i=0,len=arr.length; i<len; i++)
				var item = arr[i];
				if(item.children)
					flatObj[item.id] = item.children;
					arguments.callee(item.children)
				
				// 其它逻辑代码
			
		)(arr);
		
		return flatObj;
	

具名函数递归

递归调用接口,结果组装成 map

function recursionFun(param)
	var arr = [];
    fetch('https://blog.csdn.net/jx520/getMenu?pid='+param)
    .then(response =>response.json())
    .then(jsonArray =>  
		var textArr = [];

		jsonArray.forEach(function (item, index, jsonArr) 
			if(item.isFolder)
				arr.push([[item.title] , recursionFun(item.key)]); // 有子级,递归调用
			else
				textArr.push(item.title); // 叶结点内容先压进数组,下面会转成字符串
			
        );
		
		// 有内容就压入,没有内容就跳过。
		textArr.length && arr.push(textArr.join(','));
        
    );
	return arr;


var json = recursionFun(0); // 从根节点开始

// 等异步返回结果再执行才看的到效果。
JSON.stringify(json,null,4);

格式化数据

var path = [];
var arr = [];
function recursionFun(list)
	list.forEach( (v, i) => 
		if(typeof v === "string")
			arr.push(path.join('-') + " : " + v);
		else
			path.push(v[0]);
			recursionFun(v[1]);
			path.pop();
		
	);

recursionFun(json[0][1]);
arr.join('\\n');

遍历树形结构生成SQL

tree 结构生成 sql

树型结构生成sql,用于插入mysql

var sql = [];
var tree = [
	"id":1,"pid":0,"name":"a", "id":2,"pid":1,"name":"a1",
	"id":3,"pid":1,"name":"a2", "id":4,"pid":3,"name":"a201",
	"id":5,"pid":3,"name":"a202",	"id":6,"pid":4,"name":"a20101"
];
var table = "chn"; // 表名
var fields = "pid, name"; // 字段名:父id、名称
var id = "id"; // tree对象id
var pid = "pid"; // tree对象父id
var value = "name"; // tree对象value
    
function recursionFun(tree)
    tree.forEach( (obj) => 
        var parentId = obj[pid]== 0 ? 0 : `@parentId$obj[pid]`;// 第一级pid为0
        sql.push(`INSERT INTO $table ($fields) VALUES ($parentId,'$obj[value]');`);
        sql.push(`SELECT @parentId$obj[id] := LAST_INSERT_ID();`)
	);

	tree.forEach( (obj) => 
        if(obj.children && obj.children.length)
            recursionFun(obj.children);
        
	);


recursionFun(tree);
sql.join("\\n");

直接遍历dom树生成SQL

展开树1次

document.querySelectorAll("#divXXX img[src='/img/1.gif']").forEach(e=>
    e.onclick();
);
var sql = [];
var table = "chn"; // 表名
var fields = "pid, name"; // 字段名:父id、名称

function rec(eleId, parentId)  
	parentId = (parentId == 0 || parentId) ? parentId : "@parentId"+eleId;
	eleId = eleId[0] == "#" ? eleId : "#"+eleId;
	
    document.querySelectorAll(eleId+'>div:not([id$="chl"])').forEach(ele => 
        var input = ele.querySelector('input[type="hidden"]');
        sql.push(`INSERT INTO $table ($fields) VALUES ($parentId,'$input.value');`);
        sql.push(`SELECT @parentId$ele.idchl := LAST_INSERT_ID();`)
    );
	
	document.querySelectorAll(eleId+'>div[id$="chl"]').forEach(ele => 
		if(ele.childElementCount)
			rec(ele.id);
		
    );

rec("#父id", 0);
sql.join("\\n");

给树补 id、pid

有的时候,我们拿到一个树,但是没有idpid

var tree = [
	"name":"a", "children":["name":"aa", "children":["name":"aaa1","name":"aaa2"],],
	"name":"b", "children":["name":"bb", "children":["name":"bbb1","name":"bbb2"],],
	"name":"c", "children":["name":"cc", "children":["name":"ccc1","name":"ccc2"],],
	"name":"d", "children":["name":"cc", "children":["name":"ddd1","name":"ddd2"],]
];

我们如下处理给它补上。

var pids = [0];
var i = 1;
function recursionFun(tree)
    var pid = pids.pop();

	tree.map( (item) => 
        Object.assign(item, "id": i++ , "pid":pid);
		return item;
	);

    tree.forEach( (item) => 
        var children = item.children;
        if(children && children.length)
            pids.push(item.id) 
            recursionFun(children);
        
    );

recursionFun(tree);

如果叶子节点直接是字符串

var tree = [
	"name":"a", "children":["name":"aa", "children":["aaa1","aaa2"]],
	"name":"b", "children":["name":"bb", "children":["bbb1","bbb2"]],
	"name":"c", "children":["name":"cc", "children":["ccc1","ccc2"]],
	"name":"d", "children":["name":"cc", "children":["ddd1","ddd2"]]
];
var pids = [0];
var i = 1;
function recursionFun(list)
    var pid = pids.pop();

	list.map( (item,index,arr) => 
		if(typeof item === "string")
			arr[index] = "id": i++ , "pid":pid, name: item;
		else
			Object.assign(item, "id": i++ , "pid":pid);
		
		return item;
	);

    list.forEach( (item) => 
        var children = item.children;
        if(children && children.length)
            pids.push(item.id) 
            recursionFun(children);
        
    );
    

recursionFun(obj);
console.table(obj)

递归处理对象的键值对

将键值对的处理逻辑提取出来,增加灵活性。
如果值是对象,则调用 key 处理器时,还给了类型标识 isObj = true

/**
 * 递归处理所有键值对
 * @param obj			待处理的对象
 * @param processKey	处理key的方法
 * @param processValue	处理value的方法
 */
function recursionProcessObject(obj, processKey = (k, isObj)=>k, processValue = (v)=>v) 

	function recursionFn(targetObj) 

		// 如果是数组,对每个元素调用递归处理函数
		if (Array.isArray(targetObj)) 
			return targetObj.map(v => recursionFn(v));
		
		
		// 否则:累加处理键值对。
		return Object.entries(targetObj).reduce((resultObj, [currentKey, currentValue]) => 
			// 如果是对象: 处理key并递归解析象
			if (typeof currentValue === "object") 
				return  ...resultObj, [processKey(currentKey, true)]: recursionFn(currentValue) ;
			
			
			// 使用给定的 lambda 分别处理键值对。			
			return  ...resultObj, [processKey(currentKey)]: processValue(currentValue) ;
			
		, ); // 累加器初始为 
	
	
	// 调用递归函数处理对象
	return recursionFn(obj); 


test

var obj = "a":  "b":  "c":  "d": 4;
var result = recursionProcessObject(obj, k => `$k`,  v => v*2);
console.log(JSON.stringify(result, null, 4));

    "【a】": 
        "【b】": 
            "【c】": 
                "【d】": 8
            
        
    

以上是关于JavaScript 递归的几种写法的主要内容,如果未能解决你的问题,请参考以下文章

全面理解Javascript闭包和闭包的几种写法及用途

全面理解Javascript闭包和闭包的几种写法及用途

在JavaScript中创建命名空间的几种写法

Javascript闭包和闭包的几种写法及用途

javascript创建对象的几种方式

Day_4——JavaScript复制数据的几种级别-递归实现深拷贝-数组常用的方法