JavaScript 是一种描述型脚本语言,它不同于 java 或 C# 等编译性语言, 它不需要进行编译成中间语言, 而是由浏览器进行动态地解析与执行。如果你不能理解 javaScript 语言的运行机制,或者简单地说,你不能掌握 javascript 的执行顺序,那你就犹如伯乐驾驭不了千里马
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
虽然现代浏览器可以并行的下载 JavaScript(部分浏览器),但考虑到 JavaScript 的依赖关系,他们的执行依然是按照引入顺序进行的。
本文章记录本人在学习 JavaScript 中看书理解到的一些东西,加深记忆和并且整理记录下来,方便之后的复习。
在 html 文档中的执行顺序
js 代码执行顺序比较的形象,用户可以直观的感受这种执行顺序。但是,js 代码的执行顺序是比较复杂的。有时候我们会把 js 代码写在 html 里面,而 html 文档在浏览器中解析的过程是这样:浏览器按照文档流从上到下逐步解析页面结构和信息。js 代码作为嵌入的脚本也算做 html 文档的组成部分,因此,js 代码在装载时的执行顺序也是根据脚本标签 <script> 的出现来顺序来决定。(下面一个栗子)
- <!DOCTYPE html>
- <script>
- console.log("顶部脚本");
- </script>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>
- Document
- </title>
- <script>
- console.log("头部脚本");
- </script>
- </head>
- <body>
- <script>
- console.log("页面脚本");
- </script>
- </body>
- </html>
- <script>
- console.log("底部脚本");
- </script>
还有对于通过脚本标签 <script> 的 src 属性导入的外部 js 文件脚本,它也将按照其语句出现的顺序来执行,而且执行过程是文档装载的一部分,不会因为是外部 js 文件而延期执行。
- // 先加载 b.js 并且执行里面的代码
- <script src="b.js"></script>
- // 然后在按顺序执行下面的代码
- <script>
- console.log(1);
- </script>
预编译
当 js 引擎解析的时候,它会在预编译对所有声明的变量和函数进行处理。
变量提升
- console.log(a); // undefined
- var a = 1;
- console.log(a); // 1
预解析函数
- f(); // 1
- function f() {
- console.log(1);
- };
详细:javascript 变量声明提升 (hoisting)
分块执行代码
js 是按块执行代码的,所谓代码块就是使用 <script> 标签分隔的代码段。(下面一个栗子)
- <script>
- // 代码段1
- var a = 1;
- </script>
- <script>
- // 代码段2
- function f() {
- console.log(1);
- };
- </script>
因为 js 是按代码块来执行的。浏览器在解析 html 文档流的时候,如果遇到一个 <script> 标签,则 js 会等到这个代码块都加载完之后再对代码进行预编译,然后在执行。执行完毕后,浏览器会继续解析西门的 html 文档流,同时 js 也准备好处理下一个代码块。
有个小坑,由于 js 是按块执行的,因此在一个 js 块中调用后面块声明的变量或者函数就会提示语法错误。但是不同块都属于一个全局作用域,也就是说,块之间的变量和函数是可以共享的。(下面一个栗子)
- <script>
- // 代码段1
- console.log(a);
- f();
- </script>
- <script>
- // 代码段2
- var a = 1;
- function f() {
- console.log(1);
- };
- </script>
由于 js 是按块处理代码,同时又遵循 html 文档流的解析顺序,因此在上面的栗子中会看到语法错误。但是,在文档流加载完毕后再次访问就不会出现这种错误了。(下面一个栗子)
- <script>
- window.onload = function(){ // 页面初始化事件处理函数
- // 代码段1
- console.log(a);
- f();
- }
- </script>
- <script>
- // 代码段2
- var a = 1;
- function f() {
- console.log(1);
- };
- </script>
还有为了安全起见,一般在页面初始化完毕之后才允许 js 代码执行,这样就可以避免一些网速对 js 执行的影响。同时,也避开了 html 文档流对 js 执行的限制。
综上所述,javascript 在执行时的步骤是:
1、先读入第一段代码块
2、对代码块进行语法分析,如果出现语法错误,直接执行第 5 步骤
3、对 var 变量和 function 定义的函数进行 "预编译处理"(赋值式函数是不会进行预编译处理的)
4、执行代码块,有错则报错
5、如果还有下一段代码块,则读入下一段代码块,重复步骤 2
6、结束
来源: