浏览器中的JS解析器 作用域 作用域链 全局作用域 局部作用域

版权声明:本文为博主原创文章,转载须注明出处,否则追究法律责任。 https://blog.csdn.net/qq_24831889/article/details/77941653


我们知道,当浏览器读取到<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来定义一个块级作用域的常量,并用全部大写字母来表示这是一个常量。


猜你喜欢

转载自blog.csdn.net/qq_24831889/article/details/77941653