动画:「变量提高」引起的一场"血"案 !

动画:「变量提高」引起的一场

写在前边javascript

某一外包公司小李,刚刚入门前端以后,老板就让他写一段前端 JS 项目代码,不料,这时以前学过Java的小李遇到了一个问题,对于常常写 Java代码的小李来讲,这属于一个灵异事件。项目中的一段代码以下:前端

动画:「变量提高」引起的一场

小李越想越感到纳闷,明明我在打印以前,没有声明任何的变量呀,为何还能使用未声明的变量,从而打印出 a 的值呢,是否是个人编译器出现了问题?遇到问题的小李,越想越奇怪,就又写了一段测试代码。java

动画:「变量提高」引起的一场

按理说应该输出undefined呀,为何会输出的结果为 10。小李越想越奇怪,到底哪里出现问题了。这时老板过来了,看了看代码,笑了笑说,你仍是去先学学基础吧。就这样,小李在网上找到了小鹿的这篇教程,学完以后,才恍然大悟。面试

思惟导图ide

动画:「变量提高」引起的一场

1函数

什么是变量提高?学习

咱们首先要弄明白什么是变量提高?顾名思义,从表面上的意思去分析,代码在真正的执行以前变量就已经进行了提高声明。是的,确实是这么个意思,可是咱们后边的原理部分说的这种所谓的“提高”却不是真正的提高,而是为了让开发者便于理解,才有了变量提高这以名词,话说到这,那么它是如何进行提高的呢?测试

咱们仍是用小李的例子,第一个例子以下:动画

动画:「变量提高」引起的一场

首先,程序执行,首先将声明的变量提高到最前边,a 变量就会被提高到最前边,可是并不会进行赋值操做,变量提高完毕以后,代码自上而下顺序执行。输出 a 的值,a 此时没有被赋值,因此输出 undefined,继续执行,a 被赋值 10,执行完毕。3d

动画:「变量提高」引起的一场

除此以外,其实不只变量会提高函数也会被提高。

注意:只有 var 声明的变量或函数才会进行提高,而 ES6 中的 let 和 const 不会进行提高,后面会讲到。

函数提高:

动画:「变量提高」引起的一场

函数提高优先于变量提高,函数提高会把整个函数挪到做用域顶部,变量提高只会把声明挪到做用域顶部。

2

为何须要变量提高?

小李以前有 Java基础,为什么到了 JS 有这种策略,他想不通为何要这样,顺序执行它不香吗?

别着急,咱们举个例子就说明为何 JS 中须要变量提高了。以下代码所示:

动画:「变量提高」引起的一场

咱们想想,若是 JS 没有变量提高,这个程序仍是否可以执行呢?咱们在 fn 函数中执行 fn2 函数,若是没有变量提高,此时的 fn2 尚未声明,因此找不到,抛出错误。

正是因为 JS 存在变量提高,因此程序执行,fn 和 fn2 函数提高被声明,而后再去执行下面的代码,就能够正常经过编译执行,是否是很香呢?最后得出结论为,变量提高存在的根本缘由就是为了解决函数间互相调用的状况。

3

变量提高的内部原理

要想知道变量提高的内部原理,咱们就深刻 JS引擎的工做原理。javascript代码的执行事实上是分两个阶段进行的。

一旦 JS 建立了词法环境——程序执行的环境,就会执行第一阶段。在第一阶段,没有执行代码,可是javascript引擎会访问并注册在当前词法环境中所声明的变量和函数 —— 咱们上边所说的变量和函数声明的提高。javascript在第一阶段完成以后开始执行第二阶段,代码自上而下顺序执行。

具体第一阶段是如何执行的呢?

一、若是咱们声明的是一个函数环境,那么咱们在词法环境中建立形参和函数参数的默认值,若是是非函数(全局做用域下),那么就跳过这个步骤。

2、若是是建立全局或函数环境,就扫描当前代码进行函数声明,不会扫描其余函数的函数体。可是不会扫描函数表达式或箭头函数。若是是块级做用域的话(ES6 的知识),跳过此步骤。

3、扫描当前代码进行变量声明。在函数或全局环境中,找到全部当前函数以及其余函数以外经过var声明的变量,并找到全部在其余函数或代码块以外经过let或const定义的变量。

在块级环境中,仅查找当前块中经过 let或 const定义的变量。对于所查找到的变量,若是没有赋值,则标记为 undefined;不然,对变量进行赋值。

整个处理过程以下图:

动画:「变量提高」引起的一场

咱们不少人认为,变量的声明提高至函数顶部,函数的声明提高至全局代码顶部。可是,咱们知道原理以后,并无那么简单。

声明:变量和函数的声明并无实际发生移动。只是在代码执行以前,先在词法环境中进行注册。虽然描述为提高了,而且进行了定义,这样更容易理解 JavaScript 的做用域的工做原理,可是,咱们能够经过词法环境对整个处理过程进行更深刻地理解,了解真正的原理。

4

如何解决变量提高问题?

若是咱们不想让变量或函数进行变量提高,咱们有没有好的解决办法?

有的,在 ES6 新标准中,提供了 let和 const来声明变量,若是咱们用 let和 const在声明以前使用了 a,程序就会抛出错误。咱们把这个错误叫作暂时性死区,就是说咱们不能在变量声明以前使用变量。

动画:「变量提高」引起的一场****

那么问题来了,var和 let/const声明的变量除了变量提高外,有什么本质上的区别呢?

第一,var声明的全局变量会绑定在window对象上,而 let和 const 声明的变量不会挂在到全局变量 window上。

动画:「变量提高」引起的一场

动画:「变量提高」引起的一场

第二,let和 const 区别就是,后者不能进行二次赋值。

5

大厂面试题解析

既然咱们学了这么多有关变量提高的知识,光说不练假把式,直接上大厂面试题,检测一下你是否真正的掌握了变量提高。

动画:「变量提高」引起的一场

咱们更具上边小鹿总结的规律,咱们把这个大厂的题给梳理一遍。

程序执行,建立一个执行环境(词法环境),而后下一步将能够进行提高的变量进行提高,咱们上边说过有哪几类是不能提高的?箭头函数、表达式。并且函数的提高会优先于变量的提高。说到这里,你必定知道这个题答案了,很明显的,答案为 8 。若是你没有作对,再将从头看一下文章哦!

6

小结

小李看到这里,立刻就明白了项目出现的奇怪现象,后来小李被老板升职加薪了.....

写到这里,对于每一个基础的知识点要打牢,尤为是对于初学者,前期学习来很浮躁,好比:变量提高,知道有这么一回事,可是他并不知其因此然。有的小伙伴会问,学这么详细图个什么?

这个问题问的好,之因此小鹿将技术点分享的很详细,拆解的很散,可是有句话说的好,“授人以鱼,不如授人以渔”。我但愿更能把这种学习的态度和方法分享给你们,一篇文章不止学到了一个知识点,而是可以提取出,属于本身的东西。这对你后期阅读源码等有很大的提高和帮助!

相关文章
相关标签/搜索