关于js编译的一些特性 | 青训营笔记

66 阅读3分钟

关于js编译的一些特性 | 青训营笔记

这是我参与 第四届青训营 笔记创作活动的的第4天

f34053c2a333a9b16cc462810af43c3f1bf53fc9be0a9-QuSvvl_fw658.webp

由于本人用javascript时间挺短的(八月份开始接触),因此本篇主要总结一些比较特殊,比较奇怪的一些样例。

作用域

全局作用域和局部作用域

在整个script标签起作用的为全局作用域,只在函数内部起作用的为局部作用域。

全局变量和局部变量

用过其它编程语言的都会知道,特别是java,对于变量的作用域的定义是特别严格,这里简单提一下javascript的全局变量和局部变量:看下面的代码:

    <script>
        var num_out = 10;   //全局变量
        function a(){
            num = 1011; //全局变量(函数内部直接声明,没有声明)
            var num_in = 100;  //局部变量,于外面的num毫无关系
        }
        console.log(num_in)
        //全局变量直到浏览器关闭才销毁
    </script>

在上面的代码中,num_out为全局变量,函数a可以随意的访问全局变量。

num_in为局部变量,只在函数a这块作用域中才有效,在函数外调用则会报错,因为局部变量在函数结束后则会自动销毁。

tips:未声明变量也不会报错,且该变量默认为全局变量。

块级作用域

在java中:

public class Main{
    public static void main(String [] args){
        if(true){
            int temp = 1;
            print(temp);
        }
        print(temp);
    }
}

这种代码在java是肯定过不了的,因为在if这个块级作用域中,temp不会在块级作用域之外生效。但在javascript中这种情况却允许存在。

例如在javascript:

<script>
    if(2 > 3){
        var num = 10;
    }
    console.log(num)
</script>

这样子却不会报错,因为在es6(标准)之前,javascript没有块级作用域,解决该问题可将var改为let

javascript中的let是ES6新增的关键字,let允许我们声明一个作用域或被限制在块级中的变量、语句或者表达式。let声明的变量只能是全局或者整个函数块的。

作用域链

先看下面的代码:

    <script>
        //js中采取链式查找的方式,向上查找存在的变量,若在上级不存在,则再向上查找
        var num2=20;
        function a(){
            var num2=10;
            function b(){
                console.log(num2);
            }
            b();
        }
        a();
    </script>

打开后台,结果显示10。js中查找变量的方法是从里向外找,不是从外向里。

Javascript预解析

javascript是一种解释型的脚本语言,相比其他语言例如c++/c的先编译后执行,Javascript与python差不多,边解释边运行。

javascript引擎在运行js时需要分两步,预解析代码执行,代码执行不用说,主要讲预解析

预解析其实做的工作就是把js代码中的所有varfunction声明提升到当前作用域的最前面,然后再进行代码执行。也就是变量提升函数提升,预解析步骤不做赋值和调用函数的操作。详细请看下面的代码:

<script>
    var a = 18;
    f1();
    function f1(){
        var b = 9;
        console.log(a);
        console.log(b);
        var a = '123';
    }
</script>

上面的代码运行结果可能出乎意料,我们对其进行分析,模仿js引擎的操作,对其进行预解析,结果如下:

<script>
    var a;
    function f1(){
        var b;
        var a;
        b = 9;
        console.log(a);
        console.log(b);
        a = '123';
    }
    a = 18;
    f1();
</script>

运行结果:undefined, 9。

总结

在我看来,js主要需要注意的是块作用域和预解析的问题,块作用域可以用let代替var去避免变量的误用,而预解析则需要考虑写代码时的顺序问题,毕竟运行结果在代码量大的时候不可能一行一行去分析,我们写代码还是需要有逻辑上的考量,避免运行结果的出乎意料。