众所周知,js 代码是自上而下执行的,但是在执行前,会先进行词法分析。所以 js 执行过程分为 词法分析和执行两个阶段
开始之前先介绍下形参和实参的区别
形参和实参的区别
说白了就是,形参就是函数声明时的变量,实参就是调用该函数时传入的具体参数 栗子
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
function foo(age) {
console.log(age)
var age = 25
}
age(18)
这个时候输出的 age 是 18,没什么问题,上面讲了,在分析变量声明时,如果 AO 上已经有该属性了 则不作任何修改
example2
function func(age) {
console.log(age);
var age = 25;
console.log(age);
function age() {
}
console.log(age);
}
func(18);
执行结果
function func(age) {
console.log(age); // ƒ age() {}
var age = 25;
console.log(age); // 25
function age() {}
console.log(age); // 25
}
func(18);
解析:
函数首先生成一个活动对象 AO
- 分析函数参数
形参:AO.age = undefined
实参:AO.age = 18 - 分析变量声明
声明变量的时候 AO 对象上已经存在该属性了,不作任何修改,所以 AO.age 还是 18 - 分析函数声明
第五行声明了函数 age,AO 中已经存在 age 属性了,则会被覆盖掉,即 AO.age = function age() {}
词法分析后,此时的运行过程等价于
function func(age) {
function age() {}
console.log(age);
var age = 25;
console.log(age);
console.log(age);
}
func(18);
注意
- 没有 var 或带 function 的声明 不会有变量提升
- let/const 没有变量提升,也就是说不能再定义之前调用
今天,你学废了吗~