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

时间:2023-03-09 01:20:31
JavaScript 预编译(变量提升和函数提升的原理)

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

1.变量提升

 console.log(global); // undefined
var global = 'global';
console.log(global); // global function fn () {
  console.log(a); // undefined
  var a = 'aaa';
  console.log(a); // aaa
}
fn();

疑问一:

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

2.函数提升

 console.log(f1); // function f1() {}
console.log(f2); // undefined
function f1() {}
var f2 = function() {}

疑问二:

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

疑问三:

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

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

3.预编译

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

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

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

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

变量提升:

 var global;
console.log(global); // undefined
global = 'global';
console.log(global); // global function fn () {
var a;
  console.log(a); // undefined
  a = 'aaa';
  console.log(a); // aaa
}
fn();

函数提升:

 function f1() {}
var f2;
console.log(f1);
console.log(f2);
f2 = function() {}

4.容易出错的一点

 // 调用函数,返回值1
f();
function f(){
alert(1);
} // 调用函数,返回语法错误。
f();
var f = function(){
alert(1);
}

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

5.总结

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

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