作用域
是指作用域是指程序源代码中定义变量的区域。
块级作用域
指在代码块 {} 里面定义的变量,只会在当前代码块有效,如果外层作用域下想访问该变量,会报引用错误异常。
使用关键字 let
或 const
定义块级作用域的变量。
for (let i = 0; i < 10; i++) {}
console.log(i) // ReferenceError: i is not defined
// 因为 i 是用 let 生命的,只能在 let 的作用域里使用,即 for 循环内部有效,外部作用域是访问不到的。
函数作用域
是指包裹在函数里的作用域,其中的变量或者内部函数,对外都是封闭的,即外界无法访问。
function f1() {
var a = 1;
var b = 2;
var c = 3;
}
console.log(a, b, c) // ReferenceError: a, b, c is not defined
全局作用域
是最外层的全局作用域,任何地方都可以访问得到。
在最外层作用域下使用 var 关键字会定义全局变量,也就是说会挂载在 window 对象上,或者不使用关键字 var、let、const 直接对变量名字进行赋值,JS也会自动为其创建为全局变量。
var a = 10;
function f1() {
b = 20
function f2() {
c = 30
console.log(a) // 10
}
f2()
}
f1()
// b 和 c 变量被隐式声明到全局变量了,所以能访问到,这也叫变量提升机制
console.log(b) // 20
console.log(c) // 30
// 但 a,b,c 也被挂载在 window 对象(全局作用域)上面了
console.log(window.a) // 10
console.log(window.b) // 20
console.log(window.c) // 30
词法作用域
在变量定义时决定(也叫静态作用域)。例如函数的作用域是在函数定义时决定的。
动态作用域
在变量调用时才决定。例如函数的作用域是在函数调用的时候才决定的。
基于这两种作用域的不同,于是作用域的嵌套情况也不相同。
下面来看一个案例:
var value = 1;
function foo() {
console.log(value);
}
function bar() {
var value = 2;
foo();
}
bar();
// 结果是???
- 假设JavaScript采用静态作用域,让我们分析下执行过程:
- 嵌套情况:全局作用域–>foo函数作用域–>bar函数作用域
- 于是:执行
foo
函数,先从foo
函数作用域里查找是否有局部变量value
。如果没有,就根据函数定义的位置,往外一层的作用域里查找变量,发现在全局作用域里找到变量value
,所以结果会打印 1。
- 假设JavaScript采用动态作用域,让我们分析下执行过程:
- 嵌套情况:全局作用域–>bar函数作用域–>foo函数作用域
- 于是:执行
foo
函数,依然是从foo
函数作用域里查找是否有局部变量value
。如果没有,就从调用函数的作用域,再往外一层也就是bar
函数作用域里查找value
变量,所以结果会打印 2。
- 由于JavaScript采用的是静态作用域,所以这个例子的结果是 1。