JavaScript作用域问题:预解析全局与局部作用域解析作用域链

Posted 珍惜缘份

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript作用域问题:预解析全局与局部作用域解析作用域链相关的知识,希望对你有一定的参考价值。

要想了解JS作用域问题,就要先了解浏览器的JS解析器的工作方式,当浏览器读到script脚本代码时,JS解析器便开始工作。其工作步骤主要分为两部分: 

JS解析器: 

1.“找一些东西”(预解析):var function 参数 

例:

 

   alert(a); //undefined

   var a=1;

   alert(a); //1

   function fn1(){alert(2);}

 

JS解析器会先找到var function 参数进行预解析。 

找到var定义的变量a时,解析为a = 未定义,不会读取具体值。换句话说,所有的变量,在正式运行之前,都提前赋了一个值——未定义。 

读到funtion时,解析为:fn1=function fn1(){ alert(2);}。所有的函数,在正式运行代码之前,都是整个函数块 

2.逐行解读代码: 

JS解析器在正式读取JS代码时,会先读取预解析得出的结果,所以本例会首先弹出undefined, 当正式读到a=1时,就会修改预解析时得到的值,此时弹出a的值就为1。

 

 例:

1

       alert(a); //报错

       a=1;

1

注:因为a没有var声明,所以预解析不到a的值,正式读取代码时找不到a,浏览器会报错。

 

以下是一些具体例子,会逐步加深对作用域的理解: 

例:

 

alert(a); //function a(){ alert(4);}

var a=1;

alert(a); //1

function a(){ alert(2);}

alert(a); //1

var a=3;

alert(a); //3

function a(){ alert(4);}

alert(a); //3

a(); //报错,最后解析器中保存的是3

 

分析:

 

预解析过程:

        a=...,

        a=function a(){ alert(2);}

        a=...,

        a=function a(){ alert(4);}

注:浏览器首先进行预解析,预解析结果如上方所示。浏览器在进行预解析时,遇到重名的变量和函数时,会留下函数;遇到重名的多个函数时,会留下后声明的函数。当正式读到代码时,就会修改预解析时保存的值,要记住表达式会修改预解析的值,但函数声明不会修改预解析的值。

 

例:

 

var a=1;

function fn1(){

    alert(a);        

    var a=2;

}

fn1(); //undefined

alert(a); //1

 

分析:

 

     预解析: a=未定义;

                fn1=function fn1(){

                      alert(a);

                       var a=2;

                 }

    逐行读代码: a=1;

                 预解析: a=未定义;

                 逐行读代码:a=2;

本例会进行两次预解析,如上所示,函数内定义的变量只在函数内起作用,所以最后弹出a的值为1。

 

例:

 

var a=1;

function fn1(){

       alert(a);                 

       a=2;

}

fn1(); //1

alert(a); //2

 

分析:此处函数内的a未用var声明,预解析函数时找不到任何a的信息,所以会跳到作用域外去找a,这称作作用域链,此时a=1.

 

例:

 

var a=1;

function fn1(a){

       alert(a);

       a=2;

}

fn1(); //undefined

alert(a); //1

 

分析:函数参数a相当于var a=…,所以函数进行预解析时a=未定义

 

          1. 预解析:

                 a=...,

                  function fn1(a){

                        alert(a);

                        a=2;

                  }

          2.逐行读代码:

                 全局a=1;

                 函数调用:预解析a=...;逐行读代码a=2,但函数外部全局变量a值不变

例:

 

var a=1;

function fn1(a){

       alert(a);     

       a=2;

}

fn1(a); //1:这个参数来自于全局量a=1;

alert(a); //1

 

注:在执行函数时,会先从函数参数开始读取代码,所以参数a被赋值为1.

以上是关于JavaScript作用域问题:预解析全局与局部作用域解析作用域链的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 作用域(链)预解析闭包函数

JavaScript有关作用域和预解析

JavaScript——作用域预解析对象

JavaScript——作用域预解析对象

JavaScript之作用域,作用域链和预解析

JavaScript 中的作用域预解析以及变量提升