我们知道,当浏览器读取到<script>时会调用‘JS解析器’对JavaScript代码进行解析。
解析过程至少分为两个部分:
- 解析器预解析,找到当前作用域下的变量(var)、函数(function)、参数声明(参数相当于一个局部变量);
变量预解析为undifined,
函数预解析为整个函数块,
参数预解析为undifined,
- 逐行执行代码;
表达式:= + - * / % ++ -- ! 参数
注意:参数属于表达式,可以改变预解析的值!(见案例四)
表达式可以修改预解析的值!
案例一:
var a = 1;
function fn1 () {
alert(a);
var a = 2;
}
fn1(); //undifined
alert(a); //1
首先解析器预解析,将变量 a 预解析为undifined,函数 fn1 预解析为函数块
function fn1 () {
alert(a);
var a = 2;
}
解析完成,开始逐行执行代码
第一行:将a赋值为1;
第七行:执行函数 fn1(),
首先,在fn1()的局部作用域内开始预解析:a = undifined;
然后逐行执行代码:alert(a),a此时首先从fn1的作用域中寻找,此时a = undifined;
a = 2 语句将fn1作用域内的a 赋值为2,此时a = 2,输出2;
第八行:alert(a),此时在全局作用域找a,a = 1,输出1.
案例二:
var a = 1;
function fn1 () {
alert(a);
a = 2;
}
fn1();
alert(a);
首先全局变量解析器进行预解析:a = undifined,fn1 =
function fn1 () {
alert(a);
a = 2;
}
然后逐行执行代码:a = 1;
执行fn1:
fn1预解析:无变量 函数 参数
逐行执行代码:alert(a),由于fn1作用域中无变量a,从上级全局作用域去找a = 1;
a = 2,由于fn1作用域中无变量a,将上级全局作用域中的a = 2;//在局部作用域中可以修改全局作用域的值
alert(a),此时a =2.
案例三:
var a = 1;
function fn1 (a) {
alert(a);
a = 2;
}
fn1();
alert(a);
首先全局变量解析器进行预解析:a = undifined,fn1 =
function fn1 (a) {
alert(a);
a = 2;
}
然后逐行执行代码:a = 1;
执行fn1:
fn1预解析:参数a = undifined
逐行执行代码:alert(a),a = undifined;
a = 2语句将fn1作用域中的a赋值为2,a = 2;
alert(a),此时a =1.
案例四: var a = 1;
function fn1 (a) {
alert(a);
a = 2;
}
fn1(a);
alert(a);
首先全局变量解析器进行预解析:a = undifined,fn1(a) =
function fn1 (a) {
alert(a);
a = 2;
}
然后逐行执行代码:a = 1将全局变量a赋值为1,a = 1;
执行fn1(a)://注意这个a是全局变量a!
fn1(a)预解析:参数a = undifined
逐行执行代码: 参数a改变fn1中的a为1,a=1;//参数和表达式一样也可以改变预解析的值
alert(a),a = 1;
a = 2语句将fn1作用域中的a赋值为2,a = 2;
alert(a),此时a =1.
案例五:
alert(a);
var a = 1;
alert(a);
function a () {alert(2);}
alert(a);
var a = 3
function a () {alert(4);}
alert(a);
首先预解析:变量a = undifined,
函数a = function a() {alert(2);}
变量a = undifined,
函数a = function a() {alert(4);}
变量和函数重名,留下函数;多个函数重名,留下最后一个函数声明。
则预解析过程中只留下一个预解析函数a = function a() {alert(4);}
逐行执行代码:代码执行过程中只会执行含有表达式的语句
alert(a) //function a() {alert(4);}
a = 1 //a = 1
alert(a) //1
alert(a) //1
a = 3 //a = 3
alert(a) //3
注意:只有function(){}才拥有作用域,if和for语句的{}只是表示代码块,而非作用域。
ES6中引入了let来定义一个块级作用域的变量;const来定义一个块级作用域的常量,并用全部大写字母来表示这是一个常量。