JavaScript代码运行前有一个类似编译的过程即词法分析,词法分析主要有三个步骤:
1.分析函数的参数
2.分析函数的变量声明
3.分析函数的函数声明表达式
具体步骤如下:
- 函数在运行的瞬间,生成一个活动对象(Active Object),简称AO
- 第一步:分析参数:
- 函数接收形式参数,添加到AO的属性,并且这个时候值为undefine,即AO.age=undefine
- 接收实参,添加到AO的属性,覆盖之前的undefine
- 第二步:分析变量声明:如var age;或var age=18;
- 如果上一步分析参数中AO还没有age属性,则添加AO属性为undefine,即AO.age=undefine
- 如果AO上面已经有age属性了,则不作任何修改
- 第三步:分析函数的声明:
- 如果有function age(){}把函数赋给AO.age ,覆盖上一步分析的值
例1:
function func(age) { console.log(age); var age = 25; console.log(age); function age() { } console.log(age); } func(18);
词法分析:
第一步,分析函数参数:
形参:AO.age = undefined
实参:AO.age = 18
第二步,分析局部变量:
第3行代码有var age,但此时第一步中已有AO.age = 18,故不做任何改变
即AO.age = 18
第三步,分析函数声明:
第5行代码有函数age,则将function age(){}赋给AO.age,即AO.age = function age(){}
所以,执行代码时:
第2行代码运行时拿到的age是词法分析后的AO.age,结果是:function age() {};
第3行代码:25赋给age,此时age=25;
第4行代码运行时age已被赋值为25,结果25;
第5,6行代码是一个函数表达式,所以不会做任何操作;
第7行代码运行时age仍然是25,结果也是25,运行结果如下
词法分析时应该注意var age = function age(){},这个语句,参与了第二步和第三步;
执行代码时应注意函数表达式不做任何操作,且只声明变量没赋值时,age仍然等于AO.age。
例2:
function func(age) { var age; console.log(age); var age = 25; console.log(age); function age() { } console.log(age); } func(18);
运行结果:
例3:
function func(age) { var age; console.log(age); var age = 25; console.log(age); function age() { console.log(age); } age(); console.log(age); } func(18);
运行结果:
例4:
function func(age) { var age; console.log(age); function age() { console.log(age); } age(); console.log(age); } func(18);
运行结果:
例5:
function func(age) { console.log(age); var age = function age() { console.log(age); }; age(); console.log(age); } func(18);
运行结果:
小结:
函数在运行的瞬间,需经历两个步骤:词法分析和语句执行
词法分析:
1.形参和实参,实参会覆盖实参
2.分析变量声明,如var age = 18;会提取出age=undefined,但不会执行赋值语句
3.分析函数声明,如function age(){}等同于var age = function(){},但函数体不执行
语句执行:
1.console.log(age);
2.var age = 25;
3.function age(){console.log(age);}是不执行的,age()才执行
注意事项:
1.函数声明 function age(){console.log(age);} 整体会赋给 AO.age
2.var age = function age(){console.log(age);} 属于词法分析第二步变量声明