首先先来解释一下作用域就是作用的范围,比如定义一个普通函数,该函数就会有自己的作用域,并且在函数里面定义的变量,函数外面是使用不了函数里面定义的变量的,作用域决定了代码区块中的变量和其他资源的可见性。
而作用域也分为静态作用域和动态作用域,词法作用域就是静态作用域,静态作用域在函数定义的时候就决定了,而动态作用域在函数调用时才决定。静态作用域在编译时期(词法解析阶段)就确定好了,所以也叫词法作用域。
对于编译型语言,编译步骤:词法分析->语法分析->语义检查->代码优化->字节码生成
对于解释型语言,编译步骤:语法检查->预编译期(预处理、预解析、预编译,预声明变量,在预定义函数),然后就可以执行。
javascript采用的是词法作用域。下面我们来看看例子。
function fun() {
console.log(a)
}
function bar() {
var a=3
fun()
}
var a=1
bar() // 1
在解释这个例子之前,还得讲解另一个知识点。
LHS和RHS
LSH(left-hand side)找到变量所在的容器本身,并且将对该变量进行赋值。
RHS(right-hand side)查找某个变量的值
LSH和RSH查找过程通过作用域链进行寻找。作用域链在函数定义的时候创建好。
现在说回这个例子,在fun函数要执行console.log(a),就是要找到变量a的值,但是fun函数没有变量a,所以要通过RSH查询(当前作用域=>上一级作用域=> ... => 全局作用域)找到变量a,在全局作用域里找到变量a,于是就输出1。
下面我们来看看动态作用域的例子(bash采用的是动态作用域)
#!/bin/bash
num=1
function fun1(){
echo $num
}
function fun2(){
local num=2
fun1 // 2
}
fun2
动态作用域会从检查函数调用链,查找目标变量出来,所以就可以对上面的例子继续解释,在fun1函数找不到num变量,就会从调用栈中找到上一级调用fun1的函数fun2,并且在函数fun2找到变量num,所以就会输出2。