在网络的直言片语中禹禹前行,在书本的记录中逐步加深,然而只有在实践中才能提出疑问,才能映像深刻。
我所理解的js执行过程
1.按html文档流的顺序执行js代码
HTML文档在浏览器中的解析过程是这样的:浏览器是按着文档流从上到下逐步解析页面结构和信息的。JavaScript代码作为嵌入的脚本应该也算做HTML文档的组成部分,所以JavaScript代码在装载时的执行顺序也是根据脚本标签<script>的出现顺序来确定的;
2.预编译&执行
当JavaScript引擎解析脚本时,它会在预编译期对所有声明的变量和函数进行处理。
- 在执行前会进行类似“预编译”的操作:首先会创建一个当前执行环境下的活动对象,并将那些用var申明的变量设置为活动对象的属性,但是此时这些变量的赋值都是undefined,并将那些以function定义的函数也添加为活动对象的属性,而且它们的值正是函数的定义。
- 在解释执行阶段,遇到变量需要解析时,会首先从当前执行环境的活动对象中查找,如果没有找到而且该执行环境的拥有者有prototype属性时则会从prototype链中查找,否则将会按照作用域链查找。遇到var a = ...这样的语句时会给相应的变量进行赋值(注意:变量的赋值是在解释执行阶段完成的,如果在这之前使用变量,它的值会是undefined)
function Hello(){
alert("Hello");
}
Hello();//Hello World
function Hello() {
alert("Hello World");
}
Hello();//Hello World
会看到输出两次:Hello World
其实上面的一段代码其实被JS引擎预编译为这样的形式:
var Hello = function() {
alert("Hello");
}
Hello = function() {
alert("Hello World");
}
Hello();
Hello();
我们可以看到,其实函数也是数据,也是变量,我们也可以对“函数“进行赋值(重赋值)。
alert(a);//undefined
var a=1;
alert(a); //1
释:变量初始化过程发生在执行期,而不是预编译期。在执行期,JavaScript解释器是按着代码先后顺序进行解析的,如果在前面代码行中没有为变量赋值,则JavaScript解释器会使用默认值undefined。由于在第二行中为变量a赋值了,所以在第三行代码中会提示变量a的值为1,而不是undefined。
比较以下两段代码
f(); // 调用函数,返回值1
function f(){
alert(1);
}
f(); // 调用函数,返回语法错误(缺少对象)
var f= function(){
alert(1);
}
之所以结果不同是因为:在下面一段中,定义的函数仅作为值赋值给变量f,所以在预编译期,JavaScript解释器只能够为声明变量f进行处理,而对于变量f的值,只能等到执行期时按顺序进行赋值,自然就会出现语法错误,提示找不到对象f。
虽然变量和函数声明可以在文档任意位置,但是良好的习惯应该是在所有JavaScript代码之前声明全局变量和函数,并对变量进行初始化赋值。在函数内部也是先声明变量,然后再引用。
3. 借助事件机制改变JavaScript执行顺序
就是浏览器在解析HTML文档流时,如果遇到一个<script>标签,则JavaScript解释器会等到这个代码块都加载完后,先对代码块进行预编译,然后再执行。执行完毕后,浏览器会继续解析下面的HTML文档流,同时JavaScript解释器也准备好处理下一个代码块。
由于JavaScript是按块处理代码,同时又遵循HTML文档流的解析顺序,所以有时第一次执行代码会出现错误。但是当文档流加载完毕,如果再次访问就不会出现这样的错误。
<script>
//JavaScript代码块1
window.onload= function(){ // 页面初始化事件处理函数
alert(a);
f();
}
</script>
<script>
//JavaScript代码块2
var a =1;
functionf(){
alert(1);
}
</script>
此时把访问第2块代码中的变量和函数的代码放在页面初始化事件函数中,就不会出现语法错误了。
为了安全起见,我们一般在页面初始化完毕之后才允许JavaScript代码执行,这样可以避免网速对JavaScript执行的影响,同时也避开了HTML文档流对于JavaScript执行的限制。
以上包含了函数的声明前置,编译与预编译,我们知道正常的一段js代码都是先进性预编译,然后从上到下顺序执行。
后来偶然一次发现:
function A(){
...
}
function B(){
...
}
A();
B();
类似以上这样一段,通过断点发现有时候函数A没有执行完就开始执行函数B;当时百思不得其解,首先确认的是:js是不是顺序执行??得到的结果是是。既然是,为什么会有时先执行B?后来旁边的实习生随意说了句:ajax的影响吧!顿时恍然大悟,我竟然忘了我的函数里面都用了ajax向后台异步请求数据,真是囧!
jq的ajax有两种方式:
同步:当JS代码加载到当前AJAX的时候会把页面里所有的代码停止加载,页面出先假死状态,当这个AJAX执行完毕后才会继续运行其他代码页面假死状态解除。
异步:AJAX代码运行的时候其他代码一样可以运行。
async:false//同步
async:true//异步(默认)
网友评论