likes
comments
collection
share

[译] 图解JS: 2. 变量提升Hoisting

作者站长头像
站长
· 阅读数 38

原文:  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代码时,首先做的就是对代码中的数据域创建和分配内存。这个时候还没开始执行代码,而是做执行前的准备工作。其中函数声明和变量声明的存储方式是不同的,函数会存储一个指向完整函数体的指针(或者说引用)。

[译] 图解JS: 2. 变量提升Hoisting

变量有一些区别,ES6引入了两个新的关键词用来声明变量: letconst, 通过letconst声明的变量在存储时不会进行初始化。

[译] 图解JS: 2. 变量提升Hoisting

通过var声明的变量在存储时会用undefined进行初始化.

[译] 图解JS: 2. 变量提升Hoisting

到这里创建阶段就完成了,开始执行代码。让我们看看在文件顶部(变量和函数声明之前)的3条console.log语句的输出结果会是什么。

因为函数在内存中存储了指向函数体的指针,因此我们可以在创造函数前使用它们。

[译] 图解JS: 2. 变量提升Hoisting

当我们在声明前使用var变量,程序会简单的打出其默认初始值undefined! 然后这可能导致异常行为,在大多数情况下都是无意识进行了这样的使用操作(你可能想得到真正的初始值而不是内存分配的默认undefined)😬

[译] 图解JS: 2. 变量提升Hoisting

为了避免意外引用到一个undefined的未定义变量,就像上个例子使用var一样,我们可以转为使用constlet,这两个关键词有一个“暂时性死区”的概念,即在实际声明之前的“区域”,也就是在它们初始化之前,都是“dead zone”;在dead zone试图访问变量时,就会得到一个ReferenceError(这也包括ES6类!)。

[译] 图解JS: 2. 变量提升Hoisting

当JS引擎执行到实际声明和赋值变量的语句时,内存中的初始值就会被更新,变成实际声明的初始值。

(下图编号应该是7,我会尽快更新😬)

[译] 图解JS: 2. 变量提升Hoisting

搞定!快速回顾下:

  • 在执行代码前,函数和变量都作为执行上下文存储在内存中,这被称为Hoisting.
  • 函数被存储为函数名和一个指向其函数体的指针,var变量被存储为变量名和初始值undefined,而letconst变量/常量存储时无初始值。

我们已经了解了在执行代码时发生了什么,现在我希望术语Hoisting对你来说不再那么模糊了。同样,如果仍然不太清楚也不要担心。用得越多就会越熟悉。有问题请随时找我帮忙,我很乐意帮助你!😃

转载自:https://juejin.cn/post/7207406497541767225
评论
请登录