# 作用域

作用域是指程序源代码中定义变量的区域。

作用域规定了如何查找代码,也就是确定当前执行代码对变量的访问权限。

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() 时依然有效。