今天工作需要,搜索下JS面试题,看到一个题目,大约是这样的

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

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

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

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

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

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

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

会分别弹出 2 和 4。

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

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

将题目再变化下,如下

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

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

那么,请看下面的代码

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

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

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

结果也一样,这说明JS解析器先预声明变量,再预定义函数。

小结一下:JS 在执行前会进行类似"预编译"的操作,而且先预定义变量再预定义函数。

Javascript的"预编译"思考的更多相关文章

  1. 一步一步的理解javascript的预编译

    首先,我们要知道javascript是单线程.解释性语言.所谓解释性语言,就是翻译一句执行一句.而不是通篇编译成一个文件再去执行. 其实这么说还没有这么直观,读一句执行一句那是到最后的事了.到JS执行 ...

  2. javascript的预编译和执行顺序

    原文:javascript的预编译和执行顺序 最近在复习javascript的事件处理时发现了一个问题,然后也是我来写javascript的预编译和执行顺序的问题 代码: 代码一<html> ...

  3. JavaScript的预编译和执行

    JavaScript引擎,不是逐条解释执行javascript代码,而是按照代码块一段段解释执行.所谓代码块就是使用<script>标签分隔的代码段. 整个代码块共有两个阶段,预编译阶段和 ...

  4. 还原真实,javascript之预编译 / 预解析

    今天在群里吹水时,有群友提出一个问题.我一看很简单,就立马给出了答案:因为存在变量提升,所以输出undefined.本以为无人反驳,可确招来口诛笔伐.作为写实派的我,一贯以来坚持真实是我的使命,岂能容 ...

  5. JavaScript 之 预编译 作用域,作用域链

    第一次写博客,本来是学习jQuery遇到闭包问题,发现并没有理解闭包,发现闭包牵扯的知识点太多.复习了一遍(发现自己该记住的全忘了)写在博客里,自己也是小白,希望大神们指点迷津,必将感激不尽. 我们知 ...

  6. JavaScript之预编译

    javascript是一种解释性弱类型语言,在浏览器中执行时,浏览器会先预览某段代码进行语法分析,检查语法的正确与否,然后再进行预编译,到最后才会从上往下一句一句开始执行这段代码,简单得来说可以表示为 ...

  7. JavaScript函数——预编译

    四部曲 创建AO对象 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined. 将实参值和形参值统一 在函数体内找函数声明,值赋予函数体. 权重按顺序依次增加.以下例子即可体现上述规则 ...

  8. javascript预编译和执行过程总结

    javascript相对于其它语言来说是一种弱类型的语言,在其它如java语言中,程序的执行需要有编译的阶段,而在javascript中也有类似的“预编译阶段”(javascript的预编译是以代码块 ...

  9. javaScript 预编译过程浅尝

    javaScript 预编译过程 1.创建AO对象(Activation Object) AO{ a: } 2.找形参和变量声明,将变量和形参作为AO属性名,值为undefined AO{ a:und ...

随机推荐

  1. iOS内存管理编程指南

    iOS 内存管理 目录[-] 一:基本原则 二:成员变量的内存管理 三:容器对象与内存管理 四:稀缺资源的管理 五:AutoRelease 六:其他注意事项 iOS下内存管理的基本思想就是引用计数,通 ...

  2. @SuppressWarnings—注解用法详解

    一.前言 编码时我们总会发现如下变量未被使用的警告提示: 上述代码编译通过且可以运行,但每行前面的“感叹号”就严重阻碍了我们判断该行是否设置的断点了.这时我们可以在方法前添加 @SuppressWar ...

  3. mybatis的基本配置:实体类、配置文件、映射文件、工具类 、mapper接口

    搭建项目 一:lib(关于框架的jar包和数据库驱动的jar包) 1,第一步:先把mybatis的核心类库放进lib里

  4. jquery加载页面的方法

    jquery加载页面的方法(页面加载完成就执行),建议大家看下windows.onload与$(document).ready之间的区别.   1.$(function(){ $("#a&q ...

  5. MongoDB开发学习

    如果你从来没有接触MongoDB或对MongoDB有一点了解,如果你是C#开发人员,那么你不妨花几分钟看看本文.本文将一步一步带您轻松入门. 阅读目录 一:简介 二:特点 三:下载安装和开启服务器 四 ...

  6. 一个封装较好的删除方法(Delete)

    前台的引用 @Html.ActionLink(“删除字样”,“后台的删除方法”,new{绑定id},new{@style="样式"});方法,如何要独立使用的话,一般还要使用到相应 ...

  7. iOS - OC iOS 开发体系

    1.iOS 开发技术体系 iOS 开发技术体系图: 层级 主要框架 Cocoa Touch UIKit 等 Media Core Graphics .OpenGl ES.Core Animation ...

  8. random使用

    package com.cz.test; import java.util.Random; public class RandomTest { public static void main(Stri ...

  9. [转载] tcp那些事1

    原文: http://coolshell.cn/articles/11564.html TCP是一个巨复杂的协议,因为他要解决很多问题,而这些问题又带出了很多子问题和阴暗面.所以学习TCP本身是个比较 ...

  10. bootstrap学习笔记<三>(文本,代码域,列表)

    文本对齐 .text-left:左对齐 .text-center:居中对齐 .text-right:右对齐 .text-justify:两端对齐 <p class="text-left ...