[译] 图解JS: 2. 变量提升Hoisting
原文: JavaScript Visualized(7 Part Series): 2. Hoisting - By Lydia Hallie
几乎每个JS开发者都听过hoisting,当遇到奇怪的错误去google搜索时,最后总是能在StackOverflow上得到类似的解答:“这个错误是hoisting引起的”🙃,那么什么是hoisting?(ps: scope将会在下一篇文章介绍,我喜欢让每一篇文章聚焦于小而具体的知识点)。
如果你是JS初学者,你可能有遇到过一些变量抛出undefind
, 或Reference Error
等的经历,不知所以。Hoisting通常被解释为一种将变量和函数声明提升到文件顶部的特性,但其实底层并不是真的这样挪动声明的位置,尽管最终的结果确实是这样的。
当JS引擎执行JS代码时,首先做的就是对代码中的数据域创建和分配内存。这个时候还没开始执行代码,而是做执行前的准备工作。其中函数声明和变量声明的存储方式是不同的,函数会存储一个指向完整函数体的指针(或者说引用)。
变量有一些区别,ES6引入了两个新的关键词用来声明变量: let
和const
, 通过let
和const
声明的变量在存储时不会进行初始化。
通过var
声明的变量在存储时会用undefined
进行初始化.
到这里创建阶段就完成了,开始执行代码。让我们看看在文件顶部(变量和函数声明之前)的3条console.log语句的输出结果会是什么。
因为函数在内存中存储了指向函数体的指针,因此我们可以在创造函数前使用它们。
当我们在声明前使用var
变量,程序会简单的打出其默认初始值undefined
! 然后这可能导致异常行为,在大多数情况下都是无意识进行了这样的使用操作(你可能想得到真正的初始值而不是内存分配的默认undefined
)😬
为了避免意外引用到一个undefined
的未定义变量,就像上个例子使用var
一样,我们可以转为使用const
和let
,这两个关键词有一个“暂时性死区”的概念,即在实际声明之前的“区域”,也就是在它们初始化之前,都是“dead zone”;在dead zone试图访问变量时,就会得到一个ReferenceError
(这也包括ES6类!)。
当JS引擎执行到实际声明和赋值变量的语句时,内存中的初始值就会被更新,变成实际声明的初始值。
(下图编号应该是7,我会尽快更新😬)
搞定!快速回顾下:
- 在执行代码前,函数和变量都作为执行上下文存储在内存中,这被称为Hoisting.
- 函数被存储为函数名和一个指向其函数体的指针,
var
变量被存储为变量名和初始值undefined
,而let
和const
变量/常量存储时无初始值。
我们已经了解了在执行代码时发生了什么,现在我希望术语Hoisting对你来说不再那么模糊了。同样,如果仍然不太清楚也不要担心。用得越多就会越熟悉。有问题请随时找我帮忙,我很乐意帮助你!😃
转载自:https://juejin.cn/post/7207406497541767225