前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >动图学 JavaScript 之:声明提升(Hoisting)

动图学 JavaScript 之:声明提升(Hoisting)

作者头像
savokiss
发布2019-12-17 17:50:51
4880
发布2019-12-17 17:50:51
举报
文章被收录于专栏:码力全开码力全开

背景

JS 由于语言设计的缺陷(工期不够?),里面有一些堪称神奇的特性,初学者碰到后可能会满脸黑人问号,今天要介绍的就是其中的一个特性:声明提升(Hoisting)。

如果你是一个 JS 新手,有时候会碰到 undefined 或者 ReferenceErrors 错误,而声明提升有可能就是罪魁祸首。

声明提升常常被解释为:把变量和函数放到文件的顶部,虽然表面上看起来是这样,但事实却不是如此。

编译阶段

当 JS 引擎开始解析我们的脚本,第一件事就是为我们代码中的变量 设置内存。这个阶段代码还 没有运行,只是在为后面的代码执行做准备,这个阶段就是 编译阶段

这一阶段的一部分工作就是 找到所有的声明,并用合适的作用域将它们关联起来(有关作用域的部分我们下篇再讲)。

比如 var a = 2; JS 引擎会将其看作两个声明:var a;a = 2;。第一个定义声明在编译阶段进行,第二个赋值声明会被 留在原地 等待执行阶段。

而在编译阶段中,函数声明和变量的声明存储方式是不同的。

函数声明的存储方式

函数声明的存储,在内存中存储的是整个函数的引用。(注意 函数声明函数表达式 的区别)

下图的代码,我们先看其中的函数 sum 的声明:

let 和 const 声明的变量的存储方式

变量的存储不太一样。ES6 中引入了两个新的关键字:letconst,凡是用这两个关键字定义的变量,存储的值为 uninitialized

var 声明的变量的存储方式

var 声明的变量,存储的时候默认值为 undefined

执行阶段

现在编译阶段已经完成,JS 引擎该执行代码了。我们在文件顶部添加三个 console.log 语句。

提前调用函数

上面讲过,在编译阶段由于 函数声明 存储的是整个函数的引用,所以即使在函数声明之前也可以调用函数。

提前使用 var 定义的变量

如果我们提前使用 city 这个变量,就会打印出 var 关键字定义的默认值 undefined。而大多数情况下,这个行为是令人困惑的,因为你并不期望它的值是 undefined

提前使用 const 和 let 定义的变量

正是为了解决 var 的问题,所以才会有了 constlet,当我们提前访问它们定义的变量的默认值 uninitialized 时,就会抛出 ReferenceError 。这个行为有一个霸气的名字:临时死区(Temporal Dead Zone),即你不能在这个变量初始化前访问它。

继续执行赋值操作

当 JS 引擎继续往下解释代码时,解释到某一行有赋值语句时,即会将内存中的值覆盖为代码中定义的值。

(上图中编号应该是 7 哈~)

总结

来回顾一下:

  1. 函数和变量在 编译阶段 会将声明部分存储在内存中,这就是 声明提升 (其中还涉及到 执行上下文 的概念,我们下篇再讲)
  2. 函数声明存储的是整个函数的引用,var 声明的变量存储的默认值是 undefinedletconst 声明的变量的默认值为 uninitialized

不知道有没有讲明白呢?本文翻译于作者 Lydia Hallie 的系列文章,部分内容作了详细解释,下面还有三篇,欢迎订阅公众号关注更新哈:

  • 动图学 JS 之:作用域链(Scope Chain)
  • 动图学 JS 之:事件循环(Event Loop)
  • 动图学 JS 之:JavaScript 引擎

参考资料

  • JavaScript Visualized Hoisting
  • Temporal Dead Zone
  • 你不知道的 JavaScript 上卷
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码力全开 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 编译阶段
    • 函数声明的存储方式
      • let 和 const 声明的变量的存储方式
        • var 声明的变量的存储方式
        • 执行阶段
          • 提前调用函数
            • 提前使用 var 定义的变量
              • 提前使用 const 和 let 定义的变量
                • 继续执行赋值操作
                • 总结
                • 参考资料
                相关产品与服务
                对象存储
                对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档