作用域链
通过outer去执行上下文中查找外部变量的链条
- outer:外部引用,存在于每个执行上下文的变量环境中,指向外部的执行上下文
词法作用域链
作用域是由代码中函数声明的位置来决定的,所以词法作用域是静态的作用域,通过它就能够预测代码在执行过程中如何查找标识符
- 词法作用域是代码阶段决定的,和函数调用没有关系
let count = 1
function main(){
let count = 2
function bar(){
let count = 3
function foo(){
let count = 4
}
}
}
以上代码的词法作用域链为:foo函数作用域 -> bar函数作用域 -> main函数作用域 -> 全局作用域
块级作用域变量查找
function bar() {
var myName = " 极客世界 "
let test1 = 100
if (1) {
let myName = "Chrome 浏览器 "
console.log(test) // 1
}
}
function foo() {
var myName = " 极客邦 "
let test = 2
{
let test = 3
bar()
}
}
var myName = " 极客时间 "
let myAge = 10
let test = 1
foo()
说明:bar中outer指向全局执行上下文,test为外部变量
闭包
在 JavaScript 中,根据词法作用域的规则,内部函数总是可以访问其外部函数中声明的变量,当通过调用一个外部函数返回一个内部函数后,即使该外部函数已经执行结束了,但是内部函数引用外部函数的变量依然保存在内存中,我们就把这些变量的集合称为闭包。
function foo() {
var myName = " 极客时间 "
let test1 = 1
const test2 = 2
var innerBar = {
getName:function(){
console.log(test1)
return myName
},
setName:function(newName){
myName = newName
}
}
return innerBar
}
var bar = foo()
bar.setName(" 极客邦 ")
bar.getName()
console.log(bar.getName())
说明:foo内部函数 getName 和 setName 总是可以访问他们的外部函数foo中的变量。所以即使 foo 函数已经执行结束,这两个函数依然可以使用 foo 函数中的变量 myName 和 test1。于是这两个变量仍旧会保存在调用栈中,只能由 getName 和 setName 这两个函数访问,即这两个变量成为了foo函数的闭包。
学习资料
李兵:《10丨作用域链和闭包:代码中出现相同的变量,JavaScript引擎是如何选择的?》