我理解的全局作用域和函数作用域以及递归 | 8月更文挑战

70 阅读2分钟

这是我参与8月更文挑战的第30天,活动详情查看:8月更文挑战

全局作用域和函数作用域

在ES6出来之前,js的作用域只有全局作用域和函数作用域。

我们把定义在全局作用域中的变量,成为全局变量,定义在函数里面的称之为局部变量。 他们之间有个规律:

函数里面能访问外面的变量,而函数外面不能访问函数里面的变量

举例:

var a = 1;
function fn() {
    var b = 2;
    console.log(a);//函数里面能访问外面的变量
    innerFn();
    function innerFn() {
        var c = 3;
        console.log(a);//函数里面能访问外面的变量
        console.log(b);//函数里面能访问外面的变量
    }
    fn();
}

但是如果在innerFn外面访问变量c,或者fn外面访问b或c,都会报错! 这有点像生活中的单向透视玻璃,里面能看到外面,外面看不见里面。

递归

递归就是在函数体内调用本函数

一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。

递归注意两点:

  • 找规律
  • 找出口,即边界条件,不然会导致死循环

例如:写一个方法计算n的阶层

//分析:
// n的阶层=n*(n-1)的阶层,
// (n-1)的阶层=(n-1)*(n-2)的阶层,
// .....
// 一直到
// n=1时或者n=0时得出结果(出口)

//代码如下:
function mul(n){
    if(n==0||n==1){
        return 1;
    }
    return n*mul(n-1);
}
console.log(mul(20));

若使用的是函数表达式时:

var mul = function (n){
    if(n==0||n==1){
        return 1;
    }
    return n*mul(n-1);
}
console.log(mul(20));

也可以使用arguments.callee指代本函数,但注意:在严格模式下不支持使用arguments.callee

function mul(n){
    if(n==0||n==1){
        return 1;
    }
    return n*arguments.callee(n-1);
}

递归的好处:可以让代码变得简洁,大大地减少了程序的代码量

递归的缺点:相对常用的算法如普通循环等,运行效率较低

因此,应该尽量避免使用递归,除非没有更好的算法或者某种特定情况,递归更为适合的时候。在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出