您的位置:首页 > Web前端 > JavaScript

JavaScript的预编译

2016-07-20 11:07 302 查看
JS一般都是嵌在html页面中使用,以前总认为JS也跟html一样,是完全解释执行,写在前面的代码一定会先执行。然而,事实并非如此。JS的编译和执行过程如下:

在执行之前,会先进行预编译:对function定义的函数对象,会先预编译为活动对象并添加进内存,其值为函数定义本身,如果出现同名的function,后面定义的,会将前面的覆盖;对以var声明的变量,会先为这个变量在内存中分配一个空间,但并不赋值,此时,其值为undefined。

在解释执行阶段:使用function时,会先在内存中编译的活动对象中查找,如果没有,且该执行环境的拥有者有prototype属性时则会从prototype链中查找,否则将会按照作用域链查找;遇到类似于 var a = ..形式赋值语句时,就为变量a赋值(在赋值前,变量a只是在内存中有一个空间,但值为undefined,所以在赋值前调用,就会报错。)

然后再是一行行执行所有的语句。

下面来看一些例子:

示例一:

function hello() { //先定义了一个hello函数
console.log("js");
}
hello(); //在调用之前,先进行了预编译,后面定义的hello覆盖了前面定义的,所这里输出“javascript”
function hello() {  //后面这个定义的hello函数会覆盖前面定义的hello
console.log("javasript");
}
hello(); //这里调用,当然输出“javascript”


以上这个例子,尽管从代码上看,第一次调用hello(),是在hello函数重新定义之前,但是因为在执行代码前,会有预编译,而在预编译阶段,后面定义的hello函数将前面定义的hello给覆盖了,所以,第一次调用hello()时,调用到的是覆盖后的hello,当然也就输出的是javascript了。

示例二:

f(); //执行前进行了预编译,输出“FFFF”
var f = function() { //给变量f赋值了一个匿名函数
console.log("ffff");
}
f(); //这里调用的是赋值后的变量f,输出“ffff”
function f() { //funcion定义的函数,已预编译,执行时不作处理
console.log("FFFF");
}
f(); //这里调用的还是赋值后的变量f,输出"ffff"


以上这个例子,在一开始就调了一次f(),如果完全解释执行,那里在调用前没有定义f(),应该会报错。然而有预编译这个过程,在第一次f()调用之前,就已经预编译了一个名为f的函数,可以输出“FFFF”(我认为其实输出“ffff”的也编译了,但由于其是匿名函数,则在预编译时,只是在内存中占了块空间,并没有把其赋值给任何变量),所以直接调用f(),输出的是“FFFF”。此后,遇到var f = function()… 这句时,将一个输出”ffff”的匿名函数赋值给了f,原来编译出来的f函数被覆盖了,所以在此之后调用时,都是输出为“ffff”。当解释执行再次遇到funcion f()定义时,由于在预编译时已经编译了,在解释执行时,对这些语句就不再作任何操作了。

示例三:

console.log(c); //此时c这个变量是存在的,只是没有赋值,所以输出undefined
var c = 2; //赋值在调用之后


预编译针对的是function定义的对象,对于普通的值或对象并不进行预统计,如以上例子,会输出undefined,因为在预编译阶段,只是看到var c = ..的时候,给c在内存中分配了一块空间,但并没有赋值,其值为undefined

示例四:

<script type="application/javascript">
f(); //调用之前,f还没有定义,会报错
function g() {
console.log("ggg");
}
</script>
<script type="application/javascript">
function f() {
console.log("fff");
}
g(); //调用之前,g已经定义,会正常执行
</script>


以上这个例子是将函数的定义和调用分别用两个script标签包起来,从执行的结果,可以看出,f()调用时,会报错“Uncaught ReferenceError: f is not defined”,而g()调用时,可以正常执行。这是因为JS的预编译和执行是分段进行的。先将第一个script标签中的程序预编译执行完之后,再去预编译第二个script标签中的代码,所以调用f()时,还有没f的定义,则会报错;在预编译执行第二个script标签时,第一个script标签中预编译好的对象不会被回收,本例中,就表示g()的定义依然存在,所以在第二个script标签中调用g(),是可以正常执行的。

以上可以看出,其实都是函数或变量名同名引起的,如果可以保证整个项目中没有同名的函数变量,这些问题基本上很好避免。然而,一个项目可能有很多人在开发,同名的几率非常大,这可如何是好。

请看下集:JavaScript命名空间
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息