很久以前遇到过一个面试题目,的的确确是面试官问我的问题,下面是这个问题的代码部分。由于年少无知,没有回答上,被无情pass了。

var u ='hello world';
;(function(){
alert(u);
var u = 'bonjour la monde';
})();
//请问alert的结果是什么?.

一开始毫不犹豫地想到 alert出来的是hello world; 面试官一脸无奈看着我,耸耸肩,我就大概知道被鄙视了。其实结果是undefined,但是一直没想通这样一个结果。后来才明白,JavaScript解析过程分为两个阶段,一个是预解析阶段,另外一个就是执行阶段。

执行阶段我们应该都很明白是什么意思

var u = 'hello world';
alert(u);

这段代码的结果是在浏览器中弹出出hello world不错,很简单,同样简单的还有下面的代码

alert(u);
var u = 'hello world';

结果是undefinded。因为u是在alert之后初始化的。所以按照从上到下的执行顺序来说,这样的结果是我们能够接受的。那么下面的代码呢?

u();
function u() {
alert('hello world');
}

结果是alert弹出hello world;这是为什么呢?u()明显地是在function函数上面先调用的,为什么函数能够执行呢?

其实在执行代码之前,浏览器会对js代码做预解析,解析的原则是这样的: 对该环境内用var声明变量进行提升到顶部的动作,并给它一个初始值undefined,同样,浏览器也会对function做提升动作,但是值是function返回的值,而不是undefined。并且按照命名唯一的原则,会将后声明的函数覆盖之前声明的同名函数上。如果你对上述说明不是很明白,我们可以换一种说法:浏览器在刷新的时候会悄悄地去执行。界面的js代码,不过它的执行方式是把所有在环境(window 或者 function)内声明的var 变了全部置顶并初始化为undefined。所以我们一开始面试官出题的代码在预解析之后可以等同于以下代码。

var u = 'hello world';
;(function(){}
var u;//或者var u = undefined;
alert(u);
u = 'bonjour la monde';
})();

有两个变量u,第一个是全局变量u,它是在window这个大环境内声明的,第二个是局部变量,它是在匿名函数function内声明的,因为匿名函数内包含着一个块级作用域,所以我们也可以说匿名函数内包含着一个不同于window的另一个环境。按照我们在上面提到的解析原则,在这个环境内的var变量都会提升到顶部,并且初始化为undefined,所以代码看起来就是上面的那个样子。而解析原则也会对函数提升,但是初始值不是undefined而是该函数本身,也就是说不会改变。那么下面两段代码可以说是同样的效果:

/解析前的函数
(function(){
say();
function say() {
alert('hello world');
}
});
//解析后的同效函数
(function(){
var say = function() {
alert('hello world');
}
say();
});

解析原则还包括对同名函数的覆盖,下面两段代码可以说明解析前后的状态。

//预解析前
(function () {
function say() {
alert('hello world');
} say() function say() {
alert('bonjour la monde');
}
})
//解析后的等效函数
(function(){
var say = function() {
alert('hello world')
}
var say = function() {
alert('bonjour monde')
} say();
});

现在,相信你应该对js的预解析过程有清楚的了解了。需要注意的是,用var和函数命名(function someFun())的方式声明一个函数都没有问题,这取决与项目的需要或者代码的规范或者个人的喜好,但是遇到以上的问题比如用var声明,那么在此之前你是不能够调用它的,而用function name() 方式命名,在同一个环境或者作用域内,你可以在任何地方调用它。

javascript的执行和预解析的更多相关文章

  1. javascript预解析和作用域

    JavaScript解析过程分为两个阶段: 一是:编译阶段.就是JavaScrip预解析阶段,在这个阶段JavaScript解析器将完成把JavaScript脚本代码转换到字节码; 二是:执行阶段.在 ...

  2. js 预解析

    前言 JavaScript是解释型语言是毋庸置疑的,但它是不是仅在运行时自上往下一句一句地解析的呢? 事实上或某种现象证明并不是这样的,通过<JavaScript权威指南>及网上相关资料了 ...

  3. JS预解析与变量提升

    预解析 JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的.JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析过程和代码执行过程 预解析过程 ...

  4. JavaScript-----11.预解析

    1.预解析 1.1引子 //1问 console.log(num);//报错 num未定义 //2问 console.log(num); //undefined 未报错 var num = 10; / ...

  5. 第112天:javascript中函数预解析和执行阶段

    关于javascript中的函数:  1.预解析:把所有的函数定义提前,所有的变量声明提前,变量的赋值不提前  2.执行 :从上到下执行,但有例外(setTimeout,setInterval,aja ...

  6. javaScript中的小细节-script标签中的预解析

    首先介绍预解析,虽然预解析字面意思很好理解,但是却是出坑出的最多的地方,也是bug经常会有的地方,利用好预解析的特性可以解决很多问题,并且提高代码的质量及数量,浏览器在解析代码前会把变量的声明和函数( ...

  7. js的预解析和代码执行相关规则

    JavaScript解析过程分为两个阶段,一个是编译阶段,另外一个就是执行阶段. 1.编译阶段:又称为预解析阶段,在这个阶段JavaScript解释器将完成把JavaScript脚本代码转换到字节码. ...

  8. Javascript预解析、作用域、作用域链

    最近在看js的一些资料,总结一下昨晚看到的js作用域方面的知识,不准确的地方希望留言指正! 先看片段js代码如下: < script type="text/javascript&quo ...

  9. JavaScript函数之作用域 / 作用链域 / 预解析

    关于作用域和作用链域的问题,很多文章讲的都很详细,本文属于摘录自己觉得对自己有价值的部分,留由后用,仅供参考,需要查看详细信息请点击我给出的原文链接查看原文件 做一个有爱的搬运工~~ -------- ...

随机推荐

  1. prim

    prim算法很难,但是我也把他写出来了.usaco3.1.1 #include <iostream> #include <cstring> using namespace st ...

  2. 等宽字体延伸到的 ch 长度单位和动画 animation-timing-function

    新知识点get! 等宽字体(monospaced font)是指字符宽度相同的电脑字体.与此相对,字符宽度不尽相同的电脑字体称为比例字体(proportional font). 东亚字体基本都是等宽字 ...

  3. Daily Scrum 12.14

    今日完成任务: 优化了问题页面显示问题的算法:两名开发人员有CCF考试,今天没有完成任务,任务顺延到明天. 明日任务: 黎柱金 解决资源显示全部为同一个PDF的BUG 晏旭瑞 资源搜索问题 孙思权 做 ...

  4. jetbrains产品激活方式(WebStorm,Pycharm有效)

    注册时,在打开的License Activation窗口中选择"activation code",在输入框输入下面的注册码 43B4A73YYJ-eyJsaWNlbnNlSWQiO ...

  5. 转载:分布式系统的CAP理论

    原文转载Hollis原创文章:http://www.hollischuang.com/archives/666 2000年7月,加州大学伯克利分校的Eric Brewer教授在ACM PODC会议上提 ...

  6. mysql分页原理和高效率的mysql分页查询语句

    该博来自网络转载!!!供自己学习使用!!! 以前我在mysql中分页都是用的 limit 100000,20这样的方式,我相信你也是吧,但是要提高效率,让分页的代码效率更高一些,更快一些,那我们又该怎 ...

  7. getElementsByTagName获得的不是数组的问题!

    getElementsByTag() returns a NodeList instead of an Array. You can convert a NodeList to an Array bu ...

  8. 需要了解的 Linux 网络和监控命令

    列出来的10个基础的每个linux用户都应该知道的网络和监控命令.网络和监控命令类似于这些: hostname, ping, ifconfig, iwconfig, netstat, nslookup ...

  9. 程序猿,千万别说你不了解Docker!

    放在两年前,你不认识Docker情有可原.但如果现在你还这么说,不好意思,我只能说你OUT了.你最好马上get起来,因为有可能你们公司很快就会引入Docker. 今天就和大家讨论讨论这个备受好评的应用 ...

  10. Python 第五天 模块(2)

    模块,用一砣代码实现了某个功能的代码集合. 有两种存在的方式 1.写到一个文件夹里面 2.py文件 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和 ...