1、什么是尾递归?
在函数尾部调用自身函数,是递归调用的一种特殊形式,在递归调用的过程中系统为每一层的返回点,局部变量等开辟了栈来存储,递归次数过多容易造成栈溢出,而尾递归在尾部只存在一个调用记录,可以用来优化栈溢出,降低复杂度;
举个栗子:
普通递归,实现阶乘,如下:
function factorial(n){
if(n === 1) return 1;
return n*factorial(n-1);
}
factorial(5,5) //120
使用尾递归,把变量n放在尾部自身函数里,每次执行到尾部,n不用等着再去开辟新的栈来等待,如下优化:
function factorial2(n,total){
if(n === 1) return total;
return factorial2(n-1,n*total)
}
factorial2(5,1) //120
2、尾递归应用:
数组求和:
function sum(arr,total){
if(arr.length === 1){
return total
}
return sum(arr,total+arr.pop())
}
斐波那契数列:
function factorial(n,start = 1,total = 1){
if(n < 2){
return total;
}
return factorial(n-1,total,start+total)
}
数组扁平化:
let a = [1,2,3,[4,5,6,[0,34,67]]]
function flat(arr = [],result=[]){
arr.forEach(v=>{
if(Array.isArray(v)){
result = result.concat(flat(v,[]))
}else{
result.push(v)
}
})
return result;
}
数组对象格式化:
function keysLower(obj) {
let reg = new RegExp("([A-Z]+)", "g");
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
let temp = obj[key];
if (reg.test(key.toString())) {
// 将修改后的属性名重新赋值给temp,并在对象obj内添加一个转换后的属性
temp = obj[key.replace(reg, function (result) {
return result.toLowerCase()
})] = obj[key];
// 将之前大写的键属性删除
delete obj[key];
}
// 如果属性是对象或者数组,重新执行函数
if (typeof temp === 'object' || Object.prototype.toString.call(temp) === '[object Array]') {
keysLower(temp);
}
}
}
return obj;
};
let obj = {
a: '1',
b: {
c: '2',
D: {
E: '3'
}
}
}
// 转化为如下:
let obj = {
a: '1',
b: {
c: '2',
d: {
e: '3'
}
}
}









网友评论