18888628835/Blog

深入理解词法作用域

18888628835 opened this issue · 0 comments

什么是作用域

作用域就是程序源代码中定义变量的区域,JS中按照作用域的范围可分为全局作用域跟局部作用域(块级作用域、函数作用域)

作用域主要用来规定JS引擎查找变量的访问权限。

作用域的类型有两种,动态作用域和词法作用域,词法作用域也称静态作用域。JS的作用域属于词法作用域

什么是词法作用域

词法作用域说通俗一点就是在写代码的时候就已经确定了作用域范围。

var value = 1;

function foo() {
    console.log(value);
}

function bar() {
    var value = 2;
    foo();
}

bar();

上面的代码会打印出1,也就是说,在foo这个函数定义的时候,value这个变量就已经确定了是全局作用域下的value

我们分析一下它的执行过程:
1、bar执行,作用域记录里面有个value变量,值为2。
2、foo执行,进入foo函数内
3、foo内部打印value变量,此时查找value变量
4、value不存在于foo函数内部,此时查找foo定义时词法作用域下的环境,查找上一层作用域,最后发现全局下有个value变量
5、打印value,结果为1。
以上属于JS词法作用域的执行过程,我们拿它和动态作用域做一个对比.

动态作用域

依然是上面的代码,如果打印出value的值为2,那就是动态作用域。很多语言诸如Java就是动态作用域。说白了动态作用域会按照当前的运行环境动态选择作用域范围,这样查找的变量就会发生动态变化。

动态作用域取决于函数的调用环境,如果是动态作用域的语言,那么上面代码的执行过程是这样的:

1、bar执行,作用域记录里面有个value变量,值为2。
2、foo执行,进入foo函数内
3、foo内部打印value变量,此时查找value变量
4、value不存在于foo函数内部,此时查找foo运行时的环境,发现调用foo时的作用域是bar函数,内部有个value变量
5、打印value,结果为2。

我个人觉得动态作用域更符合人类的思维。不过JS的设计也减轻阅读代码的难度。

思考

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope(); //打印出什么
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
checkscope()(); //打印出什么
var a=checkscope()
a() //打印出什么

上面的代码分别执行打印的结果是什么?

上面的答案全部都是local scope

原因很简单,只需要记住JS是词法作用域,所有变量在函数定义的时候就已经跟着作用域确定好了,所以不管是处于怎样的运行环境,始终会牢牢绑定函数checkscope内部的scope变量。

小贴士:JS的作用域是静态的,那么有什么是动态的呢?答案是this,所谓动态,就是根据运行环境变化而变化。this就是能代表变量跟随运行环境变化的关键字。