首先先做一个测试。 下面这个函数你认为应该输出Q还是A呢?
//例1
function bar(){
return myName
}
function foo(){
var myName = 'Q'
return bar()
}
var myName = "A"
foo()
那再换一种写法,这个该输出Q还是A呢?
//例2
function foo(){
var myName = 'Q'
function bar(){
return myName
}
return bar()
}
var myName = "A"
foo()
答案是例1输出A,例2输出Q。为什么会这样呢,可以看到两段代码最主要的区别就是function bar的声明位置。这里需要引入一个概念叫做词法作用域,词法作用域决定了作用域链,作用域链就是函数查找变量的一条链路。
词法作用域:词法作用域是指作用域是由代码中函数声明的位置(对应上面也就是bar()和foo()的声明位置)决定的,因此词法作用域是静态的作用域,通过它就可以预测代码在执行过程中如何查找标识符(在上面的意思就是如何找变量myName)
什么叫根据函数声明的位置决定函数的作用域,就拿例2来说
bar的函数作用域就是粉色框部分,而foo的函数作用域就是蓝色框部分,而全局作用域则是红色框框起来的部分。作用域链为
再来分析例1的情况
bar作用域依旧是粉色,foo作用域依旧是蓝色,全局作用域是红色,但是,此时bar已经不是在foo中定义的了,因此作用域链跟上面不同了。
作用域链就是函数查找变量的链路,这也就解释了为什么例1会输出A,因为bar是直接从全局作用域找的。而例2输出Q是因为bar是在foo作用域中先找的,找到然后就输出,当然如果例2中foo中没有找到就会沿着作用域链找到全局作用域中的myName,检验一下
function bar(){
return myName
}
function foo(){
return bar()
}
var myName = "A"
foo() //A
结论:再次强调词法作用域是根据函数声明位置决定的,也就是说词法作用域是在代码编译阶段就决定好的,和函数的调用位置没有关系。