先来看个常见的面试题以下:面试
var a = 10; function test(){ alert(a); //undefined var a = 20; alert(a); //20 } test();
疑问:为何呢?test()执行时,虽然a=20没有赋值,可是父级做用域里是有a=10的,不该该是undefined呀,js是按顺序执行的,此时的var num = 20;根本没有执行,因此应该是10!!你是否是也是这么认为的,就和我当初同样???函数
分析:众所周知,js代码是自上而下执行的,JavaScript并非传统的块级做用域,而是函数做用域。JavaScript引擎会在代码执行前进行词法分析,因此事实上,js运行分为此法分析和执行两个阶段。code
JavaScript代码运行前有一个相似编译的过程即词法分析,词法分析主要有三个步骤:对象
分析参数ip
再分析变量的声明作用域
分析函数声明io
具体步骤以下:编译
函数在运行的瞬间,生成一个活动对象(Active Object),简称AOfunction
第一步:分析参数:test
函数接收形式参数,添加到AO的属性,而且这个时候值为undefined,即AO.name=undefined
接收实参,添加到AO的属性,覆盖以前的undefined
第二步:分析变量声明:如var name;或var name='mary';
若是上一步分析参数中AO尚未name属性,则添加AO属性为undefined,即AO.name=undefined
若是AO上面已经有name属性了,则不做任何修改
第三步:分析函数的声明:
若是有function name(){}把函数赋给AO.name ,覆盖上一步分析的值
分析下面这个栗子:
1.var a = 10; 2.function test(a){ 3. alert(a); //function a (){} 4. var a = 20; 5. alert(a); //20 6. function a (){} 7. alert(a); //20 8. } 9. 10.test(100);
词法分析:
第一步,分析函数参数:
形式参数:AO.a = undefined 接收实参:AO.a = 100
第二步,分析局部变量:
第4行代码有var a,可是此时已有AO.a = 100,因此不作任何修改,即AO.a = 100
第三步,分析函数声明:
第6行代码有函数a,则将function a(){}赋给AO.a,即AO.a = function a(){}
执行代码时:
第3行代码运行时拿到的a时词法分析后的AO.a,即AO.a = function a(){}; 第4行代码:将20赋值给a,此时a=20; 第5行代码运行时a已经被赋值为20,结果20; 第6行代码是一个函数表达式,因此不作任何操做; 第7行代码运行时还是20;
ps:
1.var a = 10; 2.function test(a){ 3. var a; //证实词法分析第二步。 4. alert(a); //100 5. a = 20; 6. alert(a); //20 7.} 7.test(100);
ps:
var a = 10; function test(a){ alert(a); //100 var a = 20; alert(a); //20 a = function(){} //是赋值,只有在执行时才有效 alert(a); //function(){} } test(100);
ps:(执行结果同上)
var a = 10; function test(a){ alert(a); //100 var a = 20; alert(a); //20 var a = function(){} //是赋值,只有在执行时才有效 alert(a); //function(){} } test(100);
补充说明:函数声明与函数表达式
//函数声明 function a(){ } //函数表达式 var b = function(){ }
a和b在词法分析时,区别:
a在词法分析时,就发挥做用; b只有在执行阶段,才发挥做用。
词法做用域
所谓词法做用域是说,其做用域为在定义时(词法分析时)就肯定下来的,而并不是在执行时肯定。白话就是在函数未执行前,函数执行的顺序已经被肯定,而不是相似JAVA同样,是在执行前根本不知道执行顺序。