`

理解Javascript中的预编译

阅读更多
今天工作需要,搜索下JS面试题,看到一个题目,大约是这样的
Js代码

  1. <script>  
  2. var x = 1, y = z = 0;  
  3. function add(n) {  
  4. n = n+1;  
  5.   }  
  6.  
  7. y = add(x);  
  8.  
  9. function add(n) {  
  10. n = n + 3;  
  11. }  
  12.  
  13. z = add(x);  
  14. </script>  

<script>
  var x = 1, y = z = 0;
  function add(n) {
  n = n+1;
  }

  y = add(x);
   
  function add(n) {
  n = n + 3;
  }

  z = add(x);
</script>



问执行完毕后 x, y, z 的值分别是多少?

仔细看的人马上就知道了, x, y 和 z 分别是 1, undefined 和 undefined。

不过,如果将两个 add 函数修改一下,题目变为
Js代码

  1. <script>  
  2. var x = 1, y = z = 0;  
  3. function add(n) {  
  4. return n = n+1;  
  5.   }  
  6.  
  7. y = add(x);  
  8.  
  9. function add(n) {  
  10. return n = n + 3;  
  11. }  
  12.  
  13. z = add(x);  
  14. </script>  

<script>
  var x = 1, y = z = 0;
  function add(n) {
  return n = n+1;
  }

  y = add(x);
   
  function add(n) {
  return n = n + 3;
  }

  z = add(x);
</script>


那么这时 y 和 z 分别是什么呢?我马上想到是 2 和 4,不过结果却是 4 和 4。
这说明,在第一次调用 add 函数之前,第二个 add 函数已经覆盖了第一个 add 函数。原来,这是 JS 解释器的"预编译",JS 解析器在执行语句前会将函数声明和变量定义进行"预编译",而这个"预编译",并非一个页面一个页面地"预编译",而是一段一段地预编译,所谓的段就是一个 <script> 块。且看下面的代码
Js代码

  1. <script>  
  2. function add(n) {  
  3. return n = n+1;  
  4.   }  
  5. alert(add(1));  
  6. </script>  
  7.  
  8. <script>  
  9. function add(n) {  
  10. return n = n+3;  
  11.   }  
  12. alert(add(1));  
  13. </script>  

<script>
  function add(n) {
  return n = n+1;
  }
  alert(add(1));
</script>

<script>
  function add(n) {
  return n = n+3;
  }
  alert(add(1));
</script>



会分别弹出 2 和 4。

那么,将上面的题目再变换一下,如下
Js代码

  1. <script>  
  2. alert( typeof addA);  
  3. addA();  
  4. function addA() {  
  5. alert( "A executed!" );  
  6. };  
  7. </script>  
  8. <script>  
  9. alert( typeof addB);  
  10. addB();  
  11. var addB = function () {  
  12. alert( "B executed!" );  
  13. };  
  14. </script>  

<script>
  alert(typeof addA);
  addA();
  function addA() {
  alert("A executed!");
  };
</script>
<script>
  alert(typeof addB);
  addB();
  var addB = function() {
  alert("B executed!");
  };
</script>



执行结果是什么呢? 按照前面的知识,第一个 <script> 块执行正常,结果就是弹出 "function" 和 "A executed!" 的对话框。
那么第二个 <script> 块呢? 执行结果是弹出 "undefined" 的对话框后报 JS 错误,说 addB 不是一个 function。
有点出乎意料?呵呵,其实第一个 script 块中的 addA 一句是函数声明,当然进行了"预编译",但是第二个 script 块中的 addB 一句并非函数声明。只不过在执行这段 <script> 之前对变量进行了"预声明",因此一开始变量addB是存在的,只不过是 undefined 的(可参看http://eclipse07.iteye.com/admin/blogs/484566 )。因此执行结果便如上面所示。

将题目再变化下,如下
Js代码

  1. <script>  
  2. alert( typeof addB);  
  3. addB();  
  4. var addB = function addB() {  
  5. alert( "B executed!" );  
  6. };  
  7. </script>  

<script>
  alert(typeof addB);
  addB();
  var addB = function addB() {
  alert("B executed!");
  };
</script>


执行结果如何呢?
在 ff 下执行,与上面执行结果一样。打住,且在 IE6 下执行看看如何。
结果是弹出 "function" 和 "B executed!",一切正常。
Google 了一下,有人说这是 IE 的 BUG。

那么,请看下面的代码
Js代码

  1. <script>  
  2. alert( typeof addB);  
  3. var addB = "variable" ;  
  4. function addB() {  
  5. alert( "function addB" );  
  6. }  
  7. alert(addB);  
  8. </script>  

<script>
  alert(typeof addB);
  var addB = "variable";
  function addB() {
  alert("function addB");
  }
  alert(addB);
</script>


执行结果是"function"和"variable"。
JS解析器先预定义了 addB 变量为 undefined, 但是 addB 函数覆盖了此变量,因此一开始执行结果是 function,然后 addB 被赋值为 "variable",因此最后执行结果是 "variable",上面的代码即使变为
Js代码

  1. <script>  
  2. alert( typeof addB);  
  3. function addB() {  
  4. alert( "function addB" );  
  5. }  
  6. var addB = "variable" ;  
  7. alert(addB);  
  8. </script>  

<script>
  alert(typeof addB);
  function addB() {
  alert("function addB");
  }
  var addB = "variable";
  alert(addB);
</script>


结果也一样,这说明JS解析器先预声明变量,再预定义函数 。
小结一下:JS 在执行前会进行类似"预编译"的操作,而且先预定义变量再预定义函数。


分享到:
评论

相关推荐

    javascript预编译思考

    JavaScript预编译是一种优化代码执行效率的技术,尤其在大型项目中尤为重要。预编译的主要目的是在实际运行前处理代码,减少解析和运行时的负担,提高应用的性能。本篇文章将深入探讨JavaScript预编译的概念、重要性...

    JavaScript作用域原理(二) 预编译[9 29]

    总结一下,JavaScript作用域和预编译是编程实践中需要深入理解的核心概念。正确掌握它们能帮助开发者写出更健壮、更易于调试的代码。在学习过程中,建议通过实践和阅读相关资料来不断加深理解,确保在日常开发中能够...

    网站的预编译

    网站的预编译是一个重要的开发流程,特别是在大型项目或者高性能网站的构建中,它能够显著提升网站的加载速度和运行效率。...对于开发者来说,理解和掌握预编译原理及工具的使用是提升工作效率和质量的重要途径。

    JavaScript 详解预编译原理

    JavaScript预编译通常发生在两个阶段:全局代码执行前和函数执行前。这个阶段涉及到创建活动对象(Active Object,简称为AO)以及全局对象(Global Object,简称为GO),并确定变量及函数的赋值位置。 具体来说,当...

    实例讲解JavaScript预编译流程

    预编译简单理解就是在内存中开辟一些空间,存放一些变量与函数 ; 2-JS预编译什么时候发生 预编译到底什么时候发生? 误以为预编译仅仅发生在script内代码块执行前 这倒并没有错 预编译确确实实在script代码内执行...

    Packem是一个预编译的通用JavaScript模块捆绑器专注于性能灵活性和可扩展性

    Packem,一个预编译的通用JavaScript模块捆绑器,是为了解决现代Web开发中的性能、灵活性和可扩展性需求而设计的。在JavaScript开发领域,模块打包是必不可少的环节,它将分散的源代码文件合并成单一的可执行文件,...

    javascript编译工具

    结合CSS预处理器如Sass或Less,JavaScript编译工具还能帮助我们将预处理器的代码转换为浏览器可识别的CSS,简化样式编写,并实现模块化管理。 总之,JavaScript编译工具是提升JavaScript开发效率的关键,它们提供了...

    简单易用的前端模板预编译工具

    它提供了一种在JavaScript中嵌入动态内容的方式,且支持预编译。 2. **Handlebars**:Handlebars提供了一个声明式的模板语言,强调数据绑定而非DOM操作。它有强大的助手函数系统,允许自定义扩展。 3. **Pug (原...

    gyp.rar v8库,用预编译v8

    7. 编译完成后,你可以将预编译的V8库集成到你的项目中,享受快速的JavaScript执行性能。 这个过程可能因具体项目需求而略有不同,但总体而言,gyp.rar文件提供了一个跨平台的方式来预编译V8,这对于在多个平台上...

    js笔记,预编译/原型/

    总结来说,JavaScript的预编译和原型机制是理解其核心概念的关键。预编译涉及变量和函数的提升,而原型则涉及对象的继承和属性查找机制。这些知识点对于任何想要深入学习JavaScript或从事前端开发的人来说都是必不可...

    浅析JavaScript预编译和暗示全局变量

    在JavaScript编程中,理解预编译和全局变量的概念至关重要,因为它们直接影响着代码的执行和变量的作用域。本文将深入探讨这两个概念。 首先,让我们来看看什么是“暗示全局变量”。在JavaScript中,如果一个变量...

    JavaScript运行过程中的“预编译阶段”和“执行阶段”

    总结来说,理解JavaScript的预编译和执行阶段对于编写可预测、可维护的JavaScript代码至关重要。掌握变量提升、函数声明与执行顺序以及作用域等方面的知识,可以有效避免在编码过程中出现常见的陷阱和错误。

    JavaScript的执行过程详细研究

    这是因为JavaScript引擎在预编译阶段会优先处理函数声明,并且允许函数重定义。因此,第二个`function Hello()`覆盖了第一个定义,导致最终执行时调用的是最后一个定义的版本。 #### 五、函数声明与函数表达式的...

    templatejs的webpakc编译loader一款javascript模板引擎

    - **高效性能**:通过预编译模板为JavaScript函数,可以在运行时快速生成HTML,提高页面渲染速度。 - **良好的隔离**:模板和业务逻辑分离,有利于代码组织和维护。 - **灵活性**:支持自定义标签和表达式,可扩展性...

    templatejs的fis编译插件一款javascript模板引擎

    2. **预编译**:这个插件将模板预先编译为JavaScript函数,这样在运行时只需要传入数据,调用这个函数即可快速生成HTML。 3. **性能提升**:通过预编译,可以避免运行时对模板的解析,从而提高渲染速度。 4. **...

    编译原理完美前端开发

    - **性能提升**:理解编译过程,可以更有效地利用缓存、预编译模板,以及理解编译器如何优化代码。 - **框架设计**:对于框架和库的开发者,编译原理是设计高效编译时特性的基础,如Vue.js的单文件组件和React的JSX...

    android.bp动态编译文档

    7. **原始备份**:`backup.zip`是原始文档,对比这个文件可以帮助你理解动态编译过程中所做的修改,以便更好地理解变化和改进。 通过以上步骤,开发者可以有效地利用`Android.bp`实现动态编译,提高构建效率,减少...

    从给定的 URL 加载. Vue 文件,并将其直接编译到 Browser.zip 中的组件

    在现代Web开发中,Vue.js 是一款非常流行的前端框架,它简化了构建用户界面的复杂性。本话题涉及的核心知识点是将Vue组件从远程URL加载并直接在...在实际项目中,通常会推荐使用预编译和按需加载策略来优化应用性能。

Global site tag (gtag.js) - Google Analytics