浅析JavaScript中的变量提升


Posted in Javascript onJune 01, 2022

前言:

JavaScript中奇怪的一点是你可以在变量和函数声明之前使用它们。就好像是变量声明和函数声明被提升了代码的顶部一样。

sayHi() // Hi there!

function sayHi() {
    console.log('Hi there!')
}
name = 'John Doe'
console.log(name)   // John Doe
var name

然而JavaScript并不会移动你的代码,所以JavaScript中“变量提升”并不是真正意义上的“提升”。

JavaScript是单线程语言,所以执行肯定是按顺序执行。但是并不是逐行的分析和执行,而是一段一段地分析执行,会先进行编译阶段然后才是执行阶段。

在编译阶段阶段,代码真正执行前的几毫秒,会检测到所有的变量和函数声明,所有这些函数和变量声明都被添加到名为Lexical Environment的JavaScript数据结构内的内存中。所以这些变量和函数能在它们真正被声明之前使用。

函数提升

sayHi() // Hi there!

function sayHi() {
    console.log('Hi there!')
}

因为函数声明在编译阶段会被添加到词法环境(Lexical Environment)中,当JavaScript引擎遇到sayHi()函数时,它会从词法环境中找到这个函数并执行它。

lexicalEnvironment = {
  sayHi: < func >
}

var变量提升

console.log(name)   // 'undefined'
var name = 'John Doe'
console.log(name)   // John Doe

上面的代码实际上分为两个部分:

  • var name表示声明变量name
  • = 'John Doe'表示的是为变量name赋值为'John Doe'。
var name    // 声明变量
name = 'John Doe' // 赋值操作

只有声明操作var name会被提升,而赋值这个操作并不会被提升,但是为什么变量name的值会是undefined呢?

原因是当JavaScript在编译阶段会找到var关键字声明的变量会添加到词法环境中,并初始化一个值undefined,在之后执行代码到赋值语句时,会把值赋值到这个变量。

// 编译阶段
lexicalEnvironment = {
  name: undefined
}
// 执行阶段
lexicalEnvironment = {
  name: 'John Doe'
}

所以函数表达式也不会被“提升”。helloWorld是一个默认值是undefined的变量,而不是一个function

helloWorld();  // TypeError: helloWorld is not a function
var helloWorld = function(){
  console.log('Hello World!');
}

let & const提升

console.log(a)  // ReferenceError: a is not defined
let a = 3

为什么会报一个ReferenceError错误,难道letconst声明的变量没有被“提升”吗?

事实上所有的声明(function, var, let, const, class)都会被“提升”。但是只有使用var关键字声明的变量才会被初始化undefined值,而letconst声明的变量则不会被初始化值。

只有在执行阶段JavaScript引擎在遇到他们的词法绑定(赋值)时,他们才会被初始化。这意味着在JavaScript引擎在声明变量之前,无法访问该变量。这就是我们所说的Temporal Dead Zone,即变量创建和初始化之间的时间跨度,它们无法访问。

如果JavaScript引擎在letconst变量被声明的地方还找不到值的话,就会被赋值为undefined或者返回一个错误(const的情况下)。

举例:

let a
console.log(a)  // undefined
a = 5

在编译阶段,JavaScript引擎遇到变量a并将它存到词法环境中,但因为使用let关键字声明的,JavaScript引擎并不会为它初始化值,所以在编译阶段,此刻的词法环境像这样:

lexicalEnvironment = {
  a: <uninitialized>
}

如果我们要在变量声明之前使用变量,JavaScript引擎会从词法环境中获取变量的值,但是变量此时还是uninitialized状态,所以会返回一个错误ReferenceError

在执行阶段,当JavaScript引擎执行到变量被声明的时候,如果声明了变量并赋值,会更新词法环境中的值,如果只是声明了变量没有被赋值,那么JavaScript引擎会给变量赋值为undefined

tips: 我们可以在letconst声明之前使用他们,只要代码不是在变量声明之前执行:

function foo() {
    console.log(name)
}
let name = 'John Doe'
foo()   // 'John Doe'

Class提升

letconst一样,class在JavaScript中也是会被“提升”的,在被真正赋值之前都不会被初始化值, 同样受Temporal Dead Zone的影响。

let peter = new Person('Peter', 25) // ReferenceError: Person is not defined
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}
let John = new Person('John', 25); 
console.log(John) // Person { name: 'John', age: 25 }

到此这篇关于浅析JavaScript中的变量提升的文章就介绍到这了,更多相关JS变量提升内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!


Tags in this post...

Javascript 相关文章推荐
JavaScript实现点击按钮后变灰避免多次重复提交
Jul 15 Javascript
javascipt匹配单行和多行注释的正则表达式
Nov 20 Javascript
解决extjs grid 不随窗口大小自适应的改变问题
Jan 26 Javascript
jQuery插件slick实现响应式移动端幻灯片图片切换特效
Apr 12 Javascript
Js+Ajax,Get和Post在使用上的区别小结
Jun 08 Javascript
jQuery插入节点和移动节点用法示例(insertAfter、insertBefore方法)
Sep 08 Javascript
JavaScript正则表达式小结(test|match|search|replace|split|exec)
Dec 08 Javascript
微信小程序 开发之快递查询功能的实现
Jan 09 Javascript
jQuery、layer实现弹出层的打开、关闭功能
Jun 28 jQuery
React-Native实现ListView组件之上拉刷新实例(iOS和Android通用)
Jul 11 Javascript
JQuery插件tablesorter表格排序实现过程解析
May 28 jQuery
JS 数组和对象的深拷贝操作示例
Jun 06 Javascript
vue ant design 封装弹窗表单的使用
Jun 01 #Vue.js
让JavaScript代码更加精简的方法技巧
Jun 01 #Javascript
cypress测试本地web应用
Jun 01 #Javascript
vue实现登陆页面开发实践
May 30 #Vue.js
Echarts如何重新渲染实例详解
May 30 #Javascript
vue router 动态路由清除方式
May 25 #Vue.js
vue如何清除浏览器历史栈
May 25 #Vue.js
You might like
PHP 中关于ord($str)&amp;gt;0x80的详细说明
2012/09/23 PHP
Thinkphp3.2实用篇之计算型验证码示例
2017/02/09 PHP
thinkPHP事务操作简单案例分析
2019/10/17 PHP
js querySelector和getElementById通过id获取元素的区别
2012/04/20 Javascript
各浏览器对document.getElementById等方法的实现差异解析
2013/12/05 Javascript
jQuery中val()方法用法实例
2014/12/25 Javascript
JavaScript调用浏览器打印功能实例分析
2015/07/17 Javascript
jquery图片滚动放大代码分享(1)
2015/08/25 Javascript
javascript生成随机数方法汇总
2015/11/12 Javascript
jQuery操作动态生成的内容的方法
2016/05/28 Javascript
Angular中$cacheFactory的作用和用法实例详解
2016/08/19 Javascript
vue中改变选中当前项的显示隐藏或者状态的实现方法
2018/02/08 Javascript
inquirer.js一个用户与命令行交互的工具详解
2019/05/18 Javascript
JS实现的碰撞检测与周期移动完整示例
2019/09/02 Javascript
vue动态设置页面title的方法实例
2020/08/23 Javascript
vue+高德地图实现地图搜索及点击定位操作
2020/09/09 Javascript
Vue+Spring Boot简单用户登录(附Demo)
2020/11/12 Javascript
[03:46]显微镜下的DOTA2第七期——满血与残血
2014/06/20 DOTA
[01:08:44]NB vs VP 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
通过代码实例展示Python中列表生成式的用法
2015/03/31 Python
pandas按若干个列的组合条件筛选数据的方法
2018/04/11 Python
对python中的 os.mkdir和os.mkdirs详解
2018/10/16 Python
解决python中使用PYQT时中文乱码问题
2019/06/17 Python
Python截图并保存的具体实例
2021/01/14 Python
HTML5 canvas基本绘图之图形变换
2016/06/27 HTML / CSS
兰蔻加拿大官方网站:Lancome加拿大
2016/08/05 全球购物
TOWER London官网:鞋子、靴子、运动鞋等
2019/07/14 全球购物
将相和教学反思
2014/02/04 职场文书
晚归检讨书
2014/02/19 职场文书
端午节活动策划方案
2014/03/09 职场文书
商务英语专业求职信
2014/06/26 职场文书
社团活动总结报告
2014/06/27 职场文书
颐和园导游词400字
2015/01/30 职场文书
催款函怎么写
2015/06/24 职场文书
三八节祝酒词
2015/08/11 职场文书
2015元旦感言
2015/12/09 职场文书