递归——函数在内部自己调用自己,那么该函数是递归函数 & 作用和循环效果一样 & 要加推出条件return,否则发生栈溢出,导致死循环 & 递归给数组中对象添加属性 & toString()和随机数
1、概念
一个方法在执行过程中调用自身,就称为递归
注意: 调用重载方法不是递归,不能光看方法名字
递归的关键: 方法调用时,程序会停在方法调用处,直到方法返回继续执行
1.1、递归的使用场景
- 一个问题可拆分为若干个子问题的解
- 拆分后的子问题与原问题除问题规模不同,解决思路相同
- 存在递归的终止条件
注意: 所谓终止条件就是不借助任何其他函数,就能直接知道求出问题答案
递归代码=终止条件+当前不借助任何方法就能实现的步骤+剩下的问题利用相同的方法解决
1.2、递归函数
一个函数在内部自己调用自己,那么这个函数就是递归函数。
递归函数的作用其实和循环效果一样。
- 循环最怕遇到的是死循环,而递归也很容易发生“栈溢出”的错误,所以必须要加推出条件return。
<script>
// 会发生栈溢出的错误
function fun(){
fun();
}
fun();
</script>
为递归函数添加return退出条件
<script>
// 输出六次
var num = 0;
function fun() {
console.log("hello"); // 会输出六次
if (num == 5) {
return; // 递归里必须加推出条件
} else {
num++;
}
fun();
}
fun();
</script>
2、使用递归代替循环
递归是函数调用自身的操作。
//依次打印1~10
for (var i = 1; i <= 10; i++) {
console.log(i);
}
//借用递归实现
function fn(e) {
console.log(++e);
if (e === 10) {
return
}
fn(e)
}
fn(0)
- 以上就利用递归实现了依次输出1~10,e初始化为0,打印e++所以输出1,当e等与10的时候结束,否则继续调用函数自身,依次类推,直至达到结束条件。
为了便于理解,示例:计算数组内元素前 n 的元素乘积。
1、使用 for 循环, 可以这样做:
<script>
let list = [1,2,3,4,5,6]
function multiply(arr, n) {
var product = 1;
for (var i = 0; i < n; i++) {
product *= arr[i];
}
return product;
}
console.log(multiply(list,4)) ; // 24
</script>
2、递归写法,注意代码里的 multiply(arr, n) == multiply(arr, n - 1) * arr[n - 1]
。 这意味着可以重写multiply以调用自身而无需依赖循环。
<script>
let list = [1,2,3,4,5,6]
function multiply(arr, n) {
if (n <= 0) {
return 1;
} else {
return multiply(arr, n - 1) * arr[n - 1];
}
}
console.log(multiply(list,4)) ; // 24
</script>
在multiply函数里,
-
n <= 0 时,返回 1。
-
在 n 比 0 大的情况里,函数会调用自身,参数 n 的值为 n - 1。
函数以相同的方式持续调用 multiply,直到 n <= 0 为止。
所以,所有函数都可以返回,原始的 multiply 返回结果。
注意: 递归函数在没有函数调用时(在这个例子中,是当 n <= 0 时)必需有一个跳出结构,否则永远不会执行完毕。
3、实例
3.1、获取数组每一项value值
<script>
let list = [2, 4, 6, 8]
//依次打印数组value值
// 1、for循环方式
for (var i = 0; i < list.length; i++) {
console.log('循环', list[i]); // 2 4 6 8
}
// 2、递归方式
function fn(arr, e) {
console.log(arr[e]); // 2 4 6 8
++e
if (e === arr.length) {
return
}
fn(arr, e)
}
fn(list, 0)
</script>
3.2、数组前几位求和
<script>
let list = [1,2,3,4,5,6]
function sum(arr, n) {
// 只修改这一行下面的代码
if(n<=0){
return 0;
}else if(n==1){
return arr[0]
}else{
return arr[n-1]+sum(arr,n-1)
}
// else if(n==1) return arr[0];
// else return arr[n-1]+sum(arr,n-1)
// 只修改这一行上面的代码
}
console.log(sum(list,4)) ; // 10
</script>
3.3、给对象数组每一个对象添加属性或增加唯一标识
<script>
let list = [{ name: '小红', id: 0 }, { name: '小明', id: 1 }]
console.log('原始',list);
//依次打印数组value值
// 1、for循环方式
for (var i = 0; i < list.length; i++) {
list[i].age = 'China'
list[i].ids = Math.random().toString(36).substr(2)
console.log('循环', list[i]);
}
// 2、递归方式
function fn(arr, e) {
arr[e].age = '中国'
arr[e].ids = Math.random().toString(36).substr(2)
console.log('递归',arr[e]);
++e
if (e === list.length) {
return
}
fn(arr, e)
}
fn(list, 0)
</script>
递归-显示
随机数
console.log(Math.random()) // 0.8187707720153985
console.log(Math.random().toString(36)) // '0.tuchtcpa9h'
console.log(Math.random().toString(36).substr(2)) // 'tuchtcpa9h'
附:toString使用方法
Number类型的toString()方法比较特殊,有默认模式和基模式两种。
1、默认模式的例子:
<script type="text/javascript">
var num1 = 10;
var num2 = 10.0;
var num3 = 10.5;
alert(num1.toString());//输出10
alert(num2.toString());//输出10
alert(num3.toString());//输出10.5
</script>
无论你用什么表示法声明数字,默认模式只是按十进制返回。
2、基模式的例子:
<script type="text/javascript">
var num1 = 10.5;
alert(num1.toString(2));//输出1010.1
alert(num1.toString(8));//输出12.4
alert(num1.toString(16));//输出a.8
</script>
很明显,基模式就是把数值型转换成相应的进制。
3.4、对象数组中,取出最后一层children数据
<script>
var data = [
{
name: "所有物品",
children: [
{
name: "水果",
children: [{ name: "苹果", children: [{ name: '青苹果' }, { name: '红苹果' }] }]
},
{
name: '主食',
children: [{ name: "米饭", children: [{ name: '北方米饭' }, { name: '南方米饭' }] }]
},
{
name: '生活用品',
children: [
{ name: "电脑类", children: [{ name: '联想电脑' }, { name: '苹果电脑' }] },
{ name: "工具类", children: [{ name: "锄头" }, { name: "锤子" }] },
{ name: "生活用品", children: [{ name: "洗发水" }, { name: "沐浴露" }] }
]
}
]
}]
// 需求:取出最后一层children数据
var recursiveFunction = function () { // 匿名函数写法
var str = ''
var getStr = function (list) {
list.forEach(item => {
if (item.children) {
getStr(item.children)
} else {
str += item.name + ';'
}
})
}
getStr(data)
console.log(str) // 青苹果;红苹果;北方米饭;南方米饭;联想电脑;苹果电脑;锄头;锤子;洗发水;沐浴露;
}
recursiveFunction()
</script>