声明:之所以分为全局预处理与函数预处理,只是为了理解方便,其实在实际运行中二者是不分先后的。
函数预处理阶段与全局预处理的差别:
- 函数每调用一次,就会产生一个LexicalEnviroment对象,在全局预处理中该对象就是window对象,但在函数预处理中该对象是不可见,无法访问的,因为他是JS解析器的东西。
- 函数是有参数的,在预处理时函数参数也会成为词法环境对象的成员;
然后函数内的声明式函数,var 声明式变量,冲突处理情况与全局的是一样的。
代码如下:
1 <body> 2 <script> 3 function f(a, b) { 4 alert(a); 5 alert(b); 6 7 var b = 100; 8 function a() { 9 10 } 11 } 12 f(1, 2); 13 </script> 14 </body>
预处理的词法环境对象如下:
1 lexcial env: { 2 a: 指向函数的引用, 3 b: 2, 4 5 //函数独有的 6 arguments: 7 } 8 9 假如有函数: 10 function xxx(a, b){ 11 12 } 13 调用时只传了一个参数 14 xxx(a); 15 那么词法环境对象为: 16 lexcial env: { 17 a: a; 18 b: undefimed 19 }
因为后面的var b 和函数 a命名冲突,所以按照原则处理,a由原本的参数被替换为函数引用,b不变,所以执行结果为函数a的字符串表示,2。
然后在执行阶段:
- 给预处理的成员赋值。
- 多个函数嵌套,每个函数都有一个LexcialEnviromment对象。
- 函数里面没有使用var声明的变量会成为最外层的LexcialEnviromment的成员,即全局变量。