作用域( scope )是指可访问变量的区域。在javascript中有三种作用域:全局作用域( global scope )、函数作用域和块级作用域( block )。

JavaScript 代码的整个执行过程,分为两个阶段,代码编译阶段和代码执行阶段。编译阶段由编译器完成,将代码翻译成可执行的代码,在这个阶段作用域会确定。执行阶段由引擎完成,主要是执行可执行代码,执行上下文在这个阶段创建。

全局作用域

不在任何函数内定义的变量都在全局作用域中。浏览器中全局作用域中的变量在所有作用域中都可以访问到:

let a = 1

function foo() {
  console.log(a)
}

function bar() {
  console.log(a + 1)
  foo()
}

bar() // 2 1

函数作用域

局部作用域即函数内部.

外部的作用域无法访问函数作用域的变量:

function foo() {
  	let a = 1
}

console.log(a) // Uncaught ReferenceError: a is not defined

块级作用域

由大括号界定。

var声明的变量没有块级作用域,该变量的作用域是所在的函数或者全局作用域。

for(var i = 0; i < 5; i++) {}

console.log(i) // 5

letconst生命的变量有块级作用域:

for(let i = 0; i < 5; i++) {}

console.log(i) // Uncaught ReferenceError: l is not defined
for(const i = 0; i < 5; i++) {}

console.log(i) // Uncaught ReferenceError: l is not defined

这里的 i 只有在{}中的才能访问到。

词法作用域(lexical scoping)

在 js 中用的是词法作用域,也叫静态作用域,即作用域在词法解析阶段就确定了,不会改变。

let a = 1

function foo() {
  console.log(a)
}

function bar() {
  let a = 2
  foo()
}

bar() //1

有静态就有动态,动态作用域是在调用时定义的。evalwith会产生动态作用域的效果,在strict模式下都会报错。

作用域链

当查找变量时,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链表就叫做作用域链。

这里只是提一下,之后会写一篇更详细的文章。

参考阅读

You Don't Know JS: Scope & Closures

[深入之词法作用域和动态作用域](https://github.com/mqyqingfeng/Blog/issues/3JavaScript)

block-MDN

es6入门