递归函数是在一个函数通过名字调用自身的情况下构成的,下面是一个经典的递归阶乘函数
递归函数的使用要注意函数终止条件避免死循环
function factorial(num){
if(num <= 1){
return 1;
}else{
return num * factorial(num - 1)
}
}
解决各个浏览器的差异
function factorial(num){
if(num <= 1){
return 1;
}else{
return num * arguments.callee(num - 1)
}
}
严格模式
var factorial = (function f(num){
if(num <= 1){
return 1;
}else{
return num * f(num - 1)
}
})
执行顺序
function abc(num){
console.log('a', num)
if(num == 3) return
abc(--num)
console.log('b', num)
}
abc(5);
// a 5
// a 4
// a 3
// b 3
// b 4
// 伪代码:
foo(5); // 一开始传了一个5进来
function abc(num){ // num = 5
console.log('a', num) // 第一行输出---a:5
if(num == 3) return
function abc(num){ // num = 4
console.log('a', num) // 第二行输出---a:4
if(num == 3) return
function abc(num){ // num = 3
console.log('a', num) // 第三行输出---a:3
if(num == 3) return
// 判断条件终止,本方法内,以下代码不会执行
function abc(num){
console.log('a', num)
if(num == 3) return
abc(--num)
console.log('b', num)
}
console.log('b', num)
}
console.log('b', num) // 由于 --num 第四行输出---b:3
}
console.log('b', num) // 由于 --num 第五行输出---b:4
}
我们知道 js 是单线程,并且有一个堆栈的概念,函数的执行是放到栈里执行的,abc(--num) 入栈顺序应该是abc(4) > abc(3),
根据`后入先出`的概念(栈就好像垃圾桶,入栈就是往垃圾桶扔垃圾,出栈就是倒垃圾),首先执行的应该是abc(3),所以先输出 b3,再输出 b4
function foo(i){
if(i == 4){
return;
}
console.log("a:" + i);
foo(i + 1);
console.log("b:" + i);
}
foo(1);
// a:1
// a:2
// a:3
// b:3
// b:2
// b:1
// 伪代码:
foo(1); // 一开始传了一个1进来
function foo(i){ // i = 1
if(i == 4) return
console.log("a:" + i); // 第一行输出---a:1
//此时执行: foo(i + 1);
function foo(i){ // i = 2
if(i == 4) return
console.log("a:" + i); // 第二行输出---a:2
function foo(i){ // i = 3
if(i == 4) return
console.log("a:" + i); // 第三行输出---a:3
function foo(i){ // i = 4
if(i == 4) return
// 以下三行代码,不会在执行了
console.log("a:" + i);
foo(i + 1);
console.log("b:" + i);
}
console.log("b:" + i); // 第四行输出---b:3
}
console.log("b:" + i); // 第五行输出---b:2
}
// 所以后面的 console.log("b:" + i); 被推到嵌套函数 foo(i + 1) 的后面了
console.log("b:" + i); // 第六行输出---b:1
}
始终记住 js 是 “解释执行” 的这个特点,执行是从上到下的。在没有异步的情况下,js 代码是不能跳过前面的代码 去执行后面的代码的