JS的预编译和执行

2016年11月06日Web前端

常说JS是一门弱类型的脚本语言,是解释执行的,实际上,他的确是解释执行的。在浏览器上,JS是要经过一个预编译的过程的,即首先进行预编译,然后在对每行解释执行。 当一个JS文件的写的比较大时,我们有时会在一个地方定义一个函数,却在很多地方使用它,即使在该函数声明的前部使用,浏览器也没有报错,如果单纯的只是按行解释执行的话,是做不到这样的。

putOut('hahah');

function putOut(str) {
    console.log(str);
}

像这样,在定义putOut的前面调用该函数,浏览器仍然在控制台输出了一串字符串。像在C/C++中,没有声明就调用肯定是会报错的。 其实,浏览器在运行JS文件的时候,会对JS有个预编译的过程,他会将function变量及var 后的变量提前,然后才会按行解释执行。

console.log(qwer);
var qwer= 'aaaa';

此时,控制台会输出的是undefined,因为var qwer= 'aaaa'相当与var qwer;和qwer = 'aaaa'这两部分组成,而通过var定义的变量名被提前了,而我们都知道,一开始不给JS变量赋值,此时他的值是undefined。所以在执行过程时,到第一行代码时,此时qwer是undefined,然后就输出了。而执行到第二行时,qwer变量被赋值了。

console.log(qwer);
qwer = '111'

当然,如果是这种情况呢?结合我们的JS知识,qwer = '111'相当与window.qwer = '111',由于在预编译的时候,没有发生变量的提前,执行时,第一行就出错了。

对于JS中的函数表达式,如果是以下的方式呢?

putOut('hahah');

var putOut = function(str) {
    console.log(str);
}

答案其实已经出现了,会报错,因为在调用函数的时候,putOut只是个undefined,所以控制台会报出Uncaught TypeError: putOut is not a function这种错误。

如果一个错误是隐藏在函数内部的呢?如:

document.onclick = function() {
    console.log(qwer);
};
console.log('2222');

实际上,该错误会在触发对应回调函数时显示。当然这也是即是JS代码中有错,有些功能却仍可运行的原因吧。

两种错误的影响

前面的及格问题,详细地说明了JS执行出错的问题。而当出现语法上的错误的时候,变无法通过预编译。会导致无法执行代码。例:

alert();
console.log(;
alert(2);

由于第二行出现了预编译报错,会导致,第一行的alert(1)都无法输出,当然第三行的更加无法执行了。 若是执行时出错了,如:

alert(1);
console.log(qwer);
alert(2);

我们会发现,会有1的弹出框,2不会出现。所以预编译出错和执行出错还是有很大的区别的。 预编译报错时,会终止预编译过程,进而导致浏览器不会去解释执行;而执行报错时,执行会在出错的那行停止,而以前的执行都是有效的,像函数定义、事件的绑定都是可以使用的。

按script块执行

如果我们是以下的代码呢?

<script type="text/javascript">
console.log(qwer);
</script>
<script type="text/javascript">
console.log('1111');
</script>

由于JS按script块为一个整体进行预编译和解释执行,所以在第一个代码块中有错,不会影响第二个代码块,所以会在控制台报错,并输出1111字符串。