JavaScript 预编译(变量提升和函数提升的原理)

本文部分内容转自https://www.cnblogs.com/CBDoctor/p/3745246.html

1.变量提升

 1 console.log(global); // undefined
 2 var global = 'global';
 3 console.log(global); // global
 4  
 5 function fn () {
 6   console.log(a); // undefined
 7   var a = 'aaa';
 8   console.log(a); // aaa
 9 }
10 fn();

疑问一:

还没有定义a和global,为什么就变成了undefined呢?

 

2.函数提升

1 console.log(f1); // function f1() {}   
2 console.log(f2); // undefined  
3 function f1() {}
4 var f2 = function() {}

疑问二:

console.log(f1)为什么能够输出还未定义初始化的f1函数呢?

疑问三:

类似于疑问一,为什么f2还没定义,就输出undefined呢?

 

这些疑问的答案,都来自JS的预编译机制:

 

3.预编译

JS并不会完全按照代码顺序进行解析执行,而是在解析之前进行一次“预编译”。在此过程中,会把:

(1)定义式的函数优先执行

(2)所有var变量定义,默认值为undefined

这就解释了上面两段代码输出的原因了,上面的两段代码我们可以用下面的形式理解:

变量提升:

 1 var global;
 2 console.log(global); // undefined
 3 global = 'global';
 4 console.log(global); // global
 5  
 6 function fn () {
 7       var a;
 8   console.log(a); // undefined
 9   a = 'aaa';
10   console.log(a); // aaa
11 }
12 fn();

函数提升:

1 function f1() {}
2 var f2;
3 console.log(f1); 
4 console.log(f2); 
5 f2 = function() {}

 

4.容易出错的一点

 1 // 调用函数,返回值1
 2 f();                                 
 3 function f(){
 4     alert(1);
 5 }
 6 
 7 // 调用函数,返回语法错误。
 8 f();                                 
 9 var f = function(){
10     alert(1);
11 }

这个一看就懂为啥了,在预编译阶段,声明了变量f,而没有为它赋值(匿名函数)。直接调用,肯定出错。

 

5.总结

  JS加载包含预编译和执行两个阶段。 编译阶段会对所有的var变量和function进行扫描,并将var变量初始化为undefined类型,而function则被初始化为函数值。

  到了执行阶段,JS从上面往下面依顺序执行,遇到var变量便进行赋值(因此,在赋值之前进行调用的话会出现错误).遇到函数变量的话会从活动对象中寻找函数

posted @ 2018-03-15 22:55  fengzw  阅读(2171)  评论(0编辑  收藏  举报