词法作用域:
- 词法作用域就是指作用域是由代码中函数声明的位置来决定的
- 词法作用域是静态的作用域,通过它就能够预测代码在执行过程中如何查找标识符。
- 内部函数总是可以访问它们的外部函数中的变量
代码如下:
function foo() {
var myName = '1'
bar()
}
function bar () {
console.log(myName)
}
var myName = '2'
foo()
分析上述代码:
全局作用域
编译阶段
执行上下文的变量环境
function foo () {...}
function bar () {...}
myName = undefined
可执行代码
myName = '2'
foo()
执行阶段, 执行maName = '2' 和 foo()
foo函数作用域
编译阶段
执行上下文的变量环境
myName = undefined
可执行代码
myName = '1'
bar()
执行阶段, 执行myName = '1' 和 bar()
bar函数作用域
编译阶段
执行上下文的变量环境
无
可执行代码
console.log(myName)
执行阶段, console.log(myName)
调用栈图示如下
outer:每个执行上下文的变量环境中,都包含了一个外部引用,用来指向外部的执行上下文
- 当JS执行全局代码的时候会先编译全局代码并创建执行上下文
- 全局代码编译完成,执行赋值操作 myName = 2
- 执行foo(), foo函数符合‘一段代码’, 需要先被编译,编译完成后执行
- foo函数编译完成,执行赋值操作 muName = 1
- 执行bar(), bar函数符合‘一段代码’, 需要先被编译,编译完成后执行
- 执行到console.log(myName)的时候, 在bar的词法环境和变量环境均未查找到myName, 便去outer指向的作用域去查找
- 此时outer指向于 全局作用域(bar函数在全局作用域的执行上下文的变量环境中被定义)
- 在全局可执行上下文中的变量环境中找到maName并打印2
如果把代码改一下,下面的代码就会打印1,原理同上
function foo() {
var myName = '1'
bar()
function bar () {
console.log(myName)
}
}
var myName = '2'
foo()