一、词法分析方法
js运行前有一个类似编译的过程即词法分析,词法分析主要有三个步骤:
- 分析参数
- 再分析变量的声明
- 分析函数说明
二、具体步骤
函数在运行的瞬间,生成一个活动对象(Active Object),简称AO
1.分析参数
- 函数接收形式参数,添加到AO的属性,并且这个时候值为undefined,即AO.age=undefined
- 接收实参,添加到AO的属性,覆盖之前的undefined
2.分析变量声明:如var age;或var age=23;
- 如果上一步分析参数中AO还没有age属性,则添加AO属性为undefined,即AO.age=undefined
- 如果AO上面已经有age属性了,则不作任何修改
3.分析函数的声明,如果有function name(){}把函数赋给AO.name ,覆盖上一步分析的值
例子1:
function t1(age) {
console.log(age);
var age = 27;
console.log(age);
function age() {}
console.log(age);
}
t1(3);
词法分析阶段:
首先形成Active Object即AO对象
分析形式参数
- AO.age = undefined
- 传入实参即对AO.age=undefined进行覆盖:AO.age = 3
分析局部变量
- 存在var age = 27;
- 这个时候遵循如果AO.age存在值则不作任何修改,按照第一步分析的最后结果AO.age = 3,所以这里不作任何修改即:AO.age = 3
分析函数的声明
- 因为函数中存在function age(){}函数
所以按照规则应该将函数赋值给AO.age覆盖第二步分析的AO.age = 3即: AO.age = function age(){}
执行阶段
- 执行t1函数,到console.log(age)时,词法分析的最后AO.age= function age(){},所以会打印:
function age(){}- var age=27;给age赋值27,到第二个console.log(age)这个时候age已经重新被赋值27,所以这个时候会打印:27
- function age() 并没有调用所以并不会执行
到第三个console.log(age)这个时候age的值并没有被再次修改,所以这个时候会打印:27
运行js查看结果如下与我们分析的完全相符:
例子2:
function t1(age) {
var age;
console.log(age);
age = 23;
console.log(age);
function age() {
console.log(age);
}
age();
console.log(age);
}
t1(22);
词法分析阶段:
首先形成Active Object即AO对象
分析形式参数
- AO.age = undefined
- 传入实参即对AO.age=undefined进行覆盖:AO.age = 22
分析局部变量
- 这个时候遵循如果AO.age存在值则不作任何修改,所以这里不作任何修改即:AO.age = 22
分析函数的声明
- 因为函数中存在function age(){}函数
所以按照规则应该将函数赋值给AO.age覆盖第二步分析的AO.age = 22即: AO.age = function age(){}
执行阶段
- 执行t1函数,到console.log(age)时,词法分析的最后AO.age= function age(){},所以会打印:
function age(){}- age = 23,这个时候会覆盖原来的function age(){console.log(age)},所以第二个console.log(age)会打印:23
function age() 并没有调用所以并不会执行
age() 这个时候的age还是23,并不是函数表达式,所以这里会报错
运行js查看结果如下与我们分析的完全相符:
三、补充说明,函数声明与函数表达式
//函数声明
function a() {}
//函数表达式
var b = function () {};
a和b在词法分析时,区别:
a在词法分析时,就发挥作用;
b只有在执行阶段,才发挥作用。
词法作用域
所谓词法作用域是说,其作用域为在定义时(词法分析时)就确定下来的,而并非在执行时确定。白话就是在函数未执行前,函数执行的顺序已经被确定,而不是类似JAVA一样,是在执行前根本不知道执行顺序。