JavaScript 作用域和变量提升

JavaScript 作用域与变量提升

JavaScript 中的作用域

在 JavaScript 中作用域分为以下三类:

  • 全局作用域: 能够被任意作用域访问.
  • 函数作用域: 可以在该函数内部访问.
  • 块级作用域: let,const 形成的块级作用域.

词法作用域与动态作用域

作用域确定当前执行代码对变量的访问权限.
词法作用域(静态作用域) wirte-time 即编程时的上下文,是指函数的作用域在函数定义时就决定了.(JavaScript等绝大数编程语言)
而动态作用域即 run-time 运行时上下文,是根据函数的调用位置.(Bash等语言)

1
2
3
4
5
6
7
8
9
var value = 1
function foo(){
console.log(value)
}
function bar(){
var value = 2
foo()
}
bar() // 1

代码解析:
执行函数 foo,先从 foo 函数内部查找是否有局部变量 value,如果没有就从书写位置查找上一层作用域,输出1.这样一层一层向上查找就形成了作用域链.

变量的生命周期与提升

变量的生命周期含: 变量声明,变量初始化,以及变量赋值三个步骤.
其中声明步骤会在作用域中注册变量,初始化步骤负责为变量分配内存并创建作用域绑定,此时变量的值是 undefined,最后变量赋值步骤分配指定值给该变量.

1
2
3
4
5
6
console.log(a) // undefined
var a = 1;
// 相当于以下代码
var a; // 变量声明及初始化 undefined
console.log(a) // undefined
a = 1; // 变量赋值

函数的生命周期与提升

不同于变量提升,在内存创建步骤,JS 解释器会通过 function 识别出函数声明,将声明,初始化,赋值三个步骤一起提升到作用域头部.需要注意的是函数表达式不属于函数声明,属于变量声明.

1
2
3
4
5
6
7
8
9
hello() // helloWorld!
function hello(){
console.log('helloWorld!')
}
sayHello() // sayHello is not a function
// 函数表达式属于变量声明,变量声明只提升变量,不提升变量的值.
var sayHello = function(){
console.log('hello!')
}