javascript的预编译和执行顺序

时间:2021-04-02 07:51:03

原文:javascript的预编译和执行顺序

   最近在复习javascript的事件处理时发现了一个问题,然后也是我来写javascript的预编译和执行顺序的问题

  代码:

代码一
<html>
<head>
<title>事件处理</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<script type='text/javascript'>
//页面在在完成加载后
window.onload=function(){
var input=document.getElementById('button');
var p=document.getElementById('p');
var i=1;
while(input){
input.onclick=function(){
p.innerHTML+='<br />('+ i +') '+this.nodeName;
}
i++;
input=input.parentNode;
}
}
</script>
</head>
<body>
<div>
<input type='button' value='Event事件' id='button' />
<p id='p'>事件捕获的顺序:</p>
</div>
</body>
</html>

显示的结果为:

aaarticlea/png;base64,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" alt="">

当我更改了代码中红色的部分后得到的结果又不相同:

代码二
<html>
<head>
<title>事件处理</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<script type='text/javascript'>
//页面在在完成加载后
window.onload=function(){
var input=document.getElementById('button');
var p=document.getElementById('p');
var i=1;
while(input){
input.onclick=function(){
p.innerHTML+='<br />('+ i++ +') '+this.nodeName;
}
input=input.parentNode;
}
}
</script>
</head>
<body>
<div>
<input type='button' value='Event事件' id='button' />
<p id='p'>事件捕获的顺序:</p>
</div>
</body>
</html>

得到的结果为:

aaarticlea/png;base64,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" alt="">

  得出这两种不同的结果那是因为javascript代码在运行时有预编译和执行两个阶段,在预编译阶段会对函数和变量进行处理,对所有的声明变量会赋值为underfined,对所有的声明函数也会赋值为函数的定义。

  下面我们来测试javascript的执行过程

  1.javascript代码执行顺序时按照脚本标签<script>出现的顺序来确定的,浏览下面页面你会发现代码是按从上到下的顺序执行的

<script type='text/javascript'>
alert('one');
</script>
<script type='text/javascript'>
alert('two');
</script>
<script type='text/javascript'>
alert('three');
</script>

   2. 因为变量在预编译时被赋予一个undefined初值,所以下面代码中,第一个变量name在代码中没有被赋值,所有就延用undefined这个值,下面的name被赋予了Jude,所以第二次输出的是Jude这个字符。

<script type='text/javascript'>
alert(name); //显示undefined
var name='Jude';
alert(name); //显示Jude
</script>

  3.从如下结果中我们知道先是连续两次输出Hello Wrold!,最后连续两次输出test,得出这样的结果是因为javascript并非是完全按照顺序执行的,而是在执行之前先进行一个预编译,预编译时声明式函数被提取出来,优先执行,而且相同的函数会进行覆盖,再执行赋值式函数。

<script type='text/javascript'>
test(); //输出Hello World!
function test(){      
alert('hello');     //声明式函数
}
test(); //输出Hello World! var test=function(){    //赋值式函数
alert('test');
}
test(); //输出test
function test(){      //声明式函数
alert('Hello World!');
}
test(); //输出test
</script>

  4.下面代码显示显示hello,再显示hello world!,这是因为javascript中的给个代码块是相互独立的,当脚本遇到第一个<script>标签时,则javascript解析器会等这个代码块加载完成后,先对它进行预编译,然后再执行之,然后javascript解析器准备解析下一个代码块,由于javascript是按块执行的,所有一个javascript调用下一个块的函数或者变量时,会出现错误

<script type='text/javascript'>
function test(){
alert('hello'); //显示hello
}
test()
</script>
<script type='text/javascript'>
function test(){
alert('hello world!'); //显示hello world!
}
test()
</script>

  5.虽然javascript是按块执行的,但不同的块却属于相同的全局作用域,不同的块的变量和函数式可以相互使用的,也就是某个块可以使用前面块的变量和函数,却不可以使用它之后的块的变量和函数

<script type='text/javascript'>
alert(name); //显示undefined
var name='Jude';
function test(){
alert('hello');
}
fun(); //不能调用下一个块的函数
</script>
<script type='text/javascript'>
alert(name); //可以调用上一个块的变量,显示Jude
test(); //可以调用上一个块的函数,显示hello
function fun(){
alert('fun');
}
</script>

  6.javascript在预编译阶段是以函数来划分作用域的,然后再通过var 声明的变量来与声明函数开辟内存空间,对var变量赋初值undefined。在执行阶段再根据作用域来嘴变量进行赋值.

  第一个代码块中函数里面的变量a是局部变量,因为a在函数内重新用var定义,所以输出undefined,而变量b是全局变量,因为在函数内没有用var重新声明b,所以在给变量b赋值时到全局变量中找全局变量b的值,所以输出的是b.

  第二个代码块中的函数内都重新声明了变量a和b,所以他们都是函数内的局部变量,所以都输出undefined。

<script type='text/javascript'>
var a='a';
var b='b';
function test(){
alert(a); //显示undefined
alert(b); //显示b
var a='test';
}
test();
</script>
<script type='text/javascript'>
var a='a';
var b='b';
function test(){
alert(a); //显示undefined
alert(b); //显示undefined
var a='test';
var b='test';
}
test();
</script>

  综上所述,javascript在执行时的步骤是:

    1、先读入第一段代码块

    2、对代码块进行语法分析,如果出现语法错误,直接执行第5步骤

    3、对var变量和function定义的函数进行“预编译处理”(赋值式函数是不会进行预编译处理的)

    4、执行代码块,有错则报错

    5、如果还有下一段代码块,则读入下一段代码块,重复步骤2

    6、结束