# 作用域
作用域是指程序源代码中定义变量的区域。
作用域规定了如何查找代码,也就是确定当前执行代码对变量的访问权限。
JavaScript 采用词法作用域(lexical scoping),也就是静态作用域。
# 静态作用域与动态作用域
因为 JavaScript 采用的是词法作用域,因此函数的作用域在函数定义的时候就已经确定了。
而与词法作用域相对的是动态作用域,函数的作用域是在函数调用的时候才决定的。
下面这个例子可以帮你分清楚两者的区别:
var value = 1
function foo() {
console.log(value)
}
function bar() {
var value = 2
foo()
}
bar()
// 结果是1
因为 JS 采用的是静态作用域,所以编译器在初次运行代码之前,会先自上而下遍历一遍所有代码,当进入 foo 函数的时候,它会首先查找是否存在局部变量 value,没有则继续往外查找直至全局。
# 动态作用域
动态作用域和静态作用域相反,一旦进入函数之后发现没有局部变量,不是直接往外查找,而是通过调用关系去一层层往外寻找。
# 思考题
var scope = 'global scope'
function checkScope() {
var scope = 'local scope'
function f() {
return scope
}
return f()
}
checkScope() // 'local scope'
var scope = 'global scope'
function checkScope() {
var scope = 'local scope'
function f() {
return scope
}
return f
}
checkScope()() // 'local scope'
两段代码都会打印 local scope
,这是因为 JS 采用词法作用域,函数作用域基于函数创建的位置。
引用《JavaScript权威指南》的回答就是
JavaScript 函数的执行用到了作用域链,这个作用域链是在函数定义的时候创建的。嵌套的函数 f() 定义在这个作用域链里,其中的变量 scope 一定是局部变量,不管何时何地执行函数 f(),这种绑定在执行 f() 时依然有效。