JavaScript预解析

1.预解析是什么

预解析是指js文件或script里的代码在正式开始执行前,进行的一些解析工作,即在全局中寻找var关键字声明的变量和function关键字声明的函数,将其声明提升到当前作用域的最顶端;代码预解析处理顺序始终从上向下,从左至右。

注意:只有var变量和函数才会发生声明提升。var 变量在声明提升是不会赋值(局部提升,仅提升var 变量)。

       预解析时,变量声明在上,函数声明在下

 

说这么多,不如直接看代码

(1)变量与函数的提升

        console.log(a);// undefined

        var a = 10;

 

        function f() {

            console.log(b);

            var b = 20;

        }

   

        f();// undefined

 

正常理解,JS代码是顺序执行,且在console.log(a)输出变量a时,a变量并未声明,此时输出a应报错才对,同理f()函数中输出变量b时,b并未声明,这也应该报错才对,但实际输出undefined并未报错。上面这段代码和下面这段代码等同

        var a

        console.log(a);// undefined

        a = 10;

 

        function f() {

            var b

            console.log(b);

            b = 20;

        }

   

        f();// undefined

 

 

由此可见,JS的预解析将变量的声明进行了提升,提升到当前作用域的最顶端。

其实JS预解析也会将函数的声明进行提升

 

       f1();// 未报错,输出f函数被调用

        function f1() {

            console.log("f函数被调用");

        }

 

 

和下面的代码的等同,

function f1() {

           console.log("f函数被调用");

        }

        f1();// f函数被调用

 

 

(2)预解析的提升位置

        function f() {

            console.log(c);// undefined

            var c = 120;

        }

 

        console.log(c);// 报错

 

变量的提升只会在当前的作用域中提升,提前到当前作用域的最上面。函数中的变量只会提升到函数作用域中的的最前面。

函数表达式预解析提升问题:

        f();// 报错 f() is not a function

        var f = function () {

            console.log("匿名函数被调用");

        };

        //和下面等同

        var f;

        f();// 报错

        f = function () {

            console.log("匿名函数被调用");

        };

 

此时会报错f is not a function,是因为函数表达式的写法其实是变量的赋值,而不是一个函数的定义,预解析只会提升var f的声明,而f=function(){…};是变量的赋值不会提升,所以报错。

 

 

 

(3)拓展:

在下面这行代码中,JS从左向右进行了预解析处理,先运算 a.x = {n: 2},再运算 a = {n: 2}

解析a.x = {n: 2}时,由于a没有x这个属性,所以在堆内存中会开辟一块地址,专门设置x的属性.

解析 a = {n: 2}时,将a重新赋值,覆盖原来的a,在堆中开辟了一块新的地址内存,此时a的地址指向了 {n: 2},然后a与 {n: 1}切断关联。

但是b的地址还是指向了原来的{n: 1},但是由于x的属性没有赋值,所以返回underfined。

 

 

JavaScript预解析

 

2.了解预解析有什么用?

和了解作用域一样,预解析虽不能使我们写出优美的代码,但是能帮助我们在开发的过程中,是我们理清思路,解答我们的一些困惑,对js的执行有更清晰的了解和认识,更轻松地应对面试和开发。