前两天我写项目的时候犯了一个非常严重但又很容易忽略的问题,现在我得好好正视它,它就是变量提升!

分析变量提升

一般来说, JavaScript在 执行的过程中,JavaScript 引擎把变量的声明部分和函数的声明部分提升到代码开头的行为就叫变量提升,看下面例子

不得不重视的JS知识点——变量提升_javascript

上面我们先解读一下代码他们的执行顺序应该是这样的

var myname = undefined;
myname = '阿木';
var age = undefined;
console.log('myname: ',myname); //myname: 阿木
console.log('myAge: ',age); //myAge: undefined
age = 20

如下图

不得不重视的JS知识点——变量提升_变量声明_02

所以当变量被提升之后呢,会给变量设置一个默认值 undefined,这种现象多多少少是有些奇怪的,因为按照一般的逻辑,变量应该在声明语句之后才可以使用。所以这个变量提升非常的神奇。

我们再看下面例子

function getNum() {
console.log(num)
var num = 1
}
getNum() //undefined

这里也会输出 undefined,因为函数内部的变量声明会被提升至函数作用域的最顶端

如果使用变量形式声明fn并在其前面执行的时候会怎么样呢?

不得不重视的JS知识点——变量提升_变量声明_03

显然它报了一个错,意思就是fn不是一个函数,因为fn只是一个变量,还没有赋值为一个函数,所以是不能执行fn方法

那如果是下面这样呢?

不得不重视的JS知识点——变量提升_变量提升_04

我们在定义这个函数之前调用它,函数仍然是可以工作。因为在 JavaScript 中执行上下文的工作方式造成的,函数会被提升上去

得出结论:

所以我们根据上面的一系列操作得出结论:

变量提升和 JavaScript 的编译过程有密不可分的关系,JavaScript 和其他语言一样,都要经历编译和执行阶段,在编译阶段内,JS 引擎会搜集所有的变量声明,然后提前让声明生效。剩下的语句需要等到执行阶段、才会生效。这就是变量提升背后的机制

我们由此举一反三,它还可以提升性能。为什么这么说呢,因为JS代码在执行之前,会进行语法检查和预编译,这个操作只会进行一次。如果没有这个操作,每次执行代码前都必须重新解析一遍该变量(函数),这是非常浪费性能的,因为变量(函数)的代码并不会改变,解析一遍就足够了。

在这个解析过程中,还会为函数生成预编译代码。统计声明了哪些变量、创建了哪些函数,并对函数的代码进行压缩,优化。这样做的好处就是每次执行函数的时候不需要再解析一遍去获取代码中声明了哪些变量,创建了哪些函数,直接为该函数分配栈空间

不得不重视的JS知识点——变量提升_javascript_05