if ("a" in window) { var a = 1; } alert(a);
先来看这个题会alert出什么呢?答案很显然会是:1javascript
不过这道题目放在之前考个人话,那我必定会答错,后来查找了一番资料,了解到两个新名词:预编译和变量提高,为了之后不会忘记,仍是留个笔记吧。java
首先来了解一下什么是预编译:对var关键字(值先设为undefined,执行时才给实际值)和函数定义式进行提早声明,再接着顺序执行代码,函数定义式在预编译时期就被解析,执行时期仍然用这个值,而不管是声明的变量仍是声明式函数,在执行的时候,能够覆盖预编译时期的值。函数
下面咱们来解释一下上面的题目为何是1呢,首先上面的代码等价于下面的代码:code
var a; if("a" in window){ a = 1; }
由于js没有块级做用域,因此if里面的也是全局的,因此在预编译过程当中里面的变量a会被提出来并被赋值为undefined,而后在执行if语句时候此时a已经存在于window中了,只不过值暂时是undefined,因而就会去执行if里面的代码,因此结果为1;ip
再来一题:作用域
var a = 1; function a(x){} alert(a); 等价于: var a; a = function(x){} a = 1; alert(a);
预编译阶段寻找代码中的var(实际将var a=1拆分为var a;a=1两部分,第一部分置顶,第二部分挂在语法树上)以及function两个关键字并置顶,在此将a以及a()分别置顶,以后在执行阶段再对a从语法树进行赋值,最后a为1。io
理解了上面的代码,下面再看一个相似的题目:编译
function a(x) { return x ; } var a; alert(a); 等价于: var a; function a(x){ return x; } alert(a);
这个题目跟上一个有点相似,可是却又不一样,缘由就是在这里a并无被赋值,而只是声明一个变量;在预编译阶段会将这种形式提早置顶,而后将function也置顶,可是function在a以后,因而预编译后两者顺序彻底倒过来了,因此最后执行结果是function a(x){return x;}。function
若是显式的给a赋值一个a=undefined;那么结果就是undefined。由于此时牵扯到赋值了 赋值的话 就在执行阶段去执行。class
Fn(); //执行结果:"执行了函数2",同名函数后者会覆盖前者 function Fn(){ //函数1 alert("执行了函数1"); } function Fn(){ //函数2 alert("执行了函数2"); }
Fn(); //执行结果:"执行了声明式函数",在预编译期声明函数及被处理了,因此即便Fn()调用函数放在声明函数前也能执行。 function Fn(){ //声明式函数 alert("执行了声明式函数"); } var Fn = function(){ //赋值式函数 alert("执行了赋值式函数"); }
经过对比上面两段代码,咱们不难发现,声明式函数与赋值式函数的区别在于:在JS的预编译期,声明式函数将会先被提取出来,而后才按顺序执行js代码,因此才有这样的结果。