JS 因为语言设计的缺陷(工期不够?),里面有一些堪称神奇的特性,初学者碰到后可能会满脸黑人问号,今天要介绍的就是其中的一个特性:声明提高(Hoisting)。javascript
若是你是一个 JS 新手,有时候会碰到 undefined
或者 ReferenceErrors
错误,而声明提高有可能就是罪魁祸首。java
声明提高
经常被解释为:把变量和函数放到文件的顶部,虽然表面上看起来是这样,但事实却不是如此。git
当 JS 引擎开始解析咱们的脚本,第一件事就是为咱们代码中的变量 设置内存。这个阶段代码还 没有运行,只是在为后面的代码执行作准备,这个阶段就是 编译阶段。github
这一阶段的一部分工做就是 找到全部的声明,并用合适的做用域将它们关联起来(有关做用域的部分咱们下篇再讲)。函数
好比 var a = 2;
JS 引擎会将其看做两个声明:var a;
和 a = 2;
。第一个定义声明在编译阶段进行,第二个赋值声明会被 留在原地
等待执行阶段。oop
而在编译阶段中,函数声明和变量的声明存储方式是不一样的。spa
函数声明的存储,在内存中存储的是整个函数的引用。(注意 函数声明 和 函数表达式 的区别)翻译
下图的代码,咱们先看其中的函数 sum
的声明:设计
变量的存储不太同样。ES6 中引入了两个新的关键字:let
和 const
,凡是用这两个关键字定义的变量,存储的值为 uninitialized
code
用 var
声明的变量,存储的时候默认值为 undefined
如今编译阶段已经完成,JS 引擎该执行代码了。咱们在文件顶部添加三个 console.log
语句。
上面讲过,在编译阶段因为 函数声明 存储的是整个函数的引用,因此即便在函数声明以前也能够调用函数。
若是咱们提早使用 city
这个变量,就会打印出 var
关键字定义的默认值 undefined
。而大多数状况下,这个行为是使人困惑的,由于你并不指望它的值是 undefined
。
正是为了解决 var
的问题,因此才会有了 const
和 let
,当咱们提早访问它们定义的变量的默认值 uninitialized
时,就会抛出 ReferenceError
。这个行为有一个霸气的名字:临时死区(Temporal Dead Zone),即你不能在这个变量初始化前访问它。
当 JS 引擎继续往下解释代码时,解释到某一行有赋值语句时,即会将内存中的值覆盖为代码中定义的值。
(上图中编号应该是 7 哈~)
来回顾一下:
var
声明的变量存储的默认值是 undefined
,let
和 const
声明的变量的默认值为 uninitialized
不知道有没有讲明白呢?本文翻译于做者 Lydia Hallie
的系列文章,部份内容做了详细解释,下面还有三篇,欢迎订阅公众号关注更新哈:
本文首发于公众号:码力全开(codingonfire)
关注并回复 副业
, 获取技术人的副业秘籍