Javascript 学习笔记(一)
最近在学习ES6的时候,看到ES6相对于ES5新增了块级作用域,在ES5中内层变量可能会覆盖外层变量,引起全局变量的污染
var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = "hello world"; } } f(); // undefined
刚开始不知道为什么输出的是undefined,后来才想起了JavaScript执行之前会有一个词法分析的过程。上面代码中,函数f执行后,输出结果为undefined
,,原因在于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。所以这里,将之前学的有JavaScript词法分析的知识整理一遍,方便已有记忆。
JavaScript代码自上而下执行,引擎负责整个代码的编译以及运行,编译器则负责词法分析、语法分析、代码生成等工作而作用于则如我们熟知的一样,负责维护所有的标识符(变量),但是在js代码执行前,会首先进行词法分析,所以事实上,js运行要分为词法分析和执行两个阶段。
词法分析:
词法分析主要分为3步
第1步:分析形参
第2步:分析变量声明
第3步:分析函数声明
如果存在函数嵌套,则从外往内进行词法分析
代码演示与分析: #1
function fn1(age,hei) {
alert(age); // 32 var age = 12; //进行赋值 AO[fn1].age=12 alert(age); // 12 alert(hei); // undefined } fn1(32);
词法分析:
在函数 fn1 调用的瞬间,会产生一个AO(Active Object)对象:
1.分析形参
① 分析函数的形参,然后将形参作为AO的属性,并且属性的值是 AO.age=undefined、AO.hei=undefined;
② 分析函数的实参列表,会把形参列表和函数内部的一个arguments对象(保存当前函数的实参列表,类似数组)形成一个一一对应的关系:arguments[0]=32;分析完实参之后,会检查arguments对象和AO对象的关系——AO.age=arguments[0]=32,AO.hei依然是undefined;
2.分析 var 声明的变量
分析函数内部 var 声明的变量,去检查AO对象上是否存在同名的属性,如果存在,则不作任何的处理;如果不存在则将变量作为AO对象的属性,并且属性的值为undedined即: AO.age=undefined;
3.分析 function 声明的函数
没有
执行过程:
alert( age ) // 32
alert( age ) //12 代码执行在这之前的 var age=12 会重新给 AO对象的 age属性赋上新的值
alert( hei ) //undefined
代码演示与分析: #2
function a(b) { alert(b); function b(){ alert(b); } b(); } a(1);
词法分析:
在函数 a 调用的瞬间,会产生一个AO(Active Object)对象:AO[a]
1.分析形参
① 分析函数的形参b,然后将形参作为AO[a]的属性,并且属性的值是 AO[a].b=undefined;
②分析传参,将实参列表与作用域链内部的arguments对象进行对比,arguments[0]=1,AO[a].b=arguments[0]=1
2.分析 var 声明的变量
没有
3.分析 function 声明的函数
分析函数内部的 function 声明的函数, 如果在AO[a]上发现了与函数名相同的属性,则直接覆盖;如果没有则将其设置成AO[a]的属性,属性的值就是这个函数的表达式:AO[a].b= function b(){ alert(b) }
执行过程:
alert(b); // function b(){ alert(b) }
b(); //执行的过程中,会在自身的 AO[b]上查找属性,如果自身不存在则会去外层的 AO上查找,如果外层还是不存在则会去全局的window上面查找,AO查找的这条连就是作用域链,所以->function b(){ alert(b) }
代码演示与分析: #3
function test(a) { console.log(a); console.log(b); var a = 10; var b = 11; console.log(a); console.log(b); var a = function () { var d =10; } function e() { var f = 10; } console.log(a()); console.log(a); console.log(a); } test(1)
词法分析:
1.分析形参
AO[test].a = undefined —> arguments[0] = 1 —> AO[test].a = arguments[0] = 1
2.分析 var 声明的变量
AO[test].a = 1 (已存在属性,不做操作) AO[test].b = undefined
3.分析 function 声明的函数
AO[test].e = function e() { var f = 10; }
执行过程:
console.log(a); // 1
console.log(b); // undefined
console.log(a); // 赋值AO[test].a = 10 —> 10
console.log(b); // 赋值AO[test].b = 11 —> 11
console.log(a()); //a方法,没有返回值。默认返回 undefined
e(); //e方法,没有返回值。默认返回 undefined
console.log(a); // AO[test].a = function { var d =10;} 当代码执行到第二个var a时,javascript引擎由于第一步编译器忽略了重复声明的var,且作用域中已经有a,所以重复声明会发生值的覆盖,但并不会报错