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变量便进行赋值(因此,在赋值之前进行调用的话会出现错误).遇到函数变量的话会从活动对象中寻找函数