JS 词法分析和变量提升

众所周知,js 代码是自上而下执行的,但是在执行前,会先进行词法分析。所以 js 执行过程分为 词法分析执行两个阶段

开始之前先介绍下形参和实参的区别

形参和实参的区别

说白了就是,形参就是函数声明时的变量,实参就是调用该函数时传入的具体参数 栗子

1
2
3
4
function add(a, b) {
return a + b
}
add(1, 2)

在声明函数 add 时 a, b 就是形参,在调用函数 add(1, 2)时 1, 2 就是实参

词法分析主要有三个步骤

  • 分析参数
  • 分析变量声明
  • 分析函数声明

函数在运行时 会生成一个活动对象 Active Object 简称 AO

  • 分析形参
    函数接收形式参数,添加到 AO 属性中,这个时候值为 undefined
    接收实参,添加到 AO 属性中,覆盖之前的 undefined
  • 分析变量声明
    在分析变量声明时,如果 AO 上已经有该属性了 则不作任何修改
    如果 AO 上还没有该属性 则为 undefined
  • 分析函数声明
    分析函数声明时 如果 AO 上已经有该属性了 则会覆盖掉

上才艺

example1

1
2
3
4
5
function foo(age) {
console.log(age)
var age = 25
}
age(18)

这个时候输出的 age 是 18,没什么问题,上面讲了,在分析变量声明时,如果 AO 上已经有该属性了 则不作任何修改

example2

1
2
3
4
5
6
7
8
function func(age) {
console.log(age)
var age = 25
console.log(age)
function age() {}
console.log(age)
}
func(18)

执行结果

1
2
3
4
5
6
7
8
function func(age) {
console.log(age) // ƒ age() {}
var age = 25
console.log(age) // 25
function age() {}
console.log(age) // 25
}
func(18)

解析:

函数首先生成一个活动对象 AO

  1. 分析函数参数
    形参:AO.age = undefined
    实参:AO.age = 18
  2. 分析变量声明
    声明变量的时候 AO 对象上已经存在该属性了,不作任何修改,所以 AO.age 还是 18
  3. 分析函数声明
    第五行声明了函数 age,AO 中已经存在 age 属性了,则会被覆盖掉,即 AO.age = function age() {}

词法分析后,此时的运行过程等价于

1
2
3
4
5
6
7
8
function func(age) {
function age() {}
console.log(age)
var age = 25
console.log(age)
console.log(age)
}
func(18)

注意

  • 没有 var 或带 function 的声明 不会有变量提升
  • let/const 没有变量提升,也就是说不能再定义之前调用

今天,你学废了吗~