浅析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 相关文章推荐
基于jquery的checkbox下拉框插件代码
Jun 25 Javascript
jQuery操作cookie方法实例教程
Nov 25 Javascript
jquery 设置style:display的方法
Jan 29 Javascript
JavaScript中的this关键字使用方法总结
Mar 13 Javascript
jquery关于事件冒泡和事件委托的技巧及阻止与允许事件冒泡的三种实现方法
Nov 27 Javascript
使用jQuery操作HTML的table表格的实例解析
Mar 13 Javascript
Javascript中获取浏览器类型和操作系统版本等客户端信息常用代码
Jun 28 Javascript
Canvas + JavaScript 制作图片粒子效果
Feb 08 Javascript
关于 angularJS的一些用法
Nov 29 Javascript
vue实现双向绑定和依赖收集遇到的坑
Nov 29 Javascript
Moment.js实现多个同时倒计时
Aug 26 Javascript
VUE前端从后台请求过来的数据进行转换数据结构操作
Nov 11 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文件上传的简单实例
2013/10/19 PHP
WordPress中邮件的一些修改和自定义技巧
2015/12/15 PHP
PHP使用DOM和simplexml读取xml文档的方法示例
2017/02/08 PHP
PHP解决中文乱码
2017/04/28 PHP
laravel-admin select框默认选中的方法
2019/10/03 PHP
如何让动态插入的javascript脚本代码跑起来。
2007/01/09 Javascript
JavaScript 以对象为索引的关联数组
2010/05/19 Javascript
Javascript面象对象成员、共享成员变量实验
2010/11/19 Javascript
网页打开自动最大化的js代码
2012/08/22 Javascript
jCallout 轻松实现气泡提示功能
2013/09/22 Javascript
js字符串完全替换函数分享
2014/12/03 Javascript
jQuery显示和隐藏 常用的状态判断方法
2015/01/29 Javascript
浅谈Vue.js应用的四种AJAX请求数据模式
2017/08/30 Javascript
详解Vue打包优化之code spliting
2018/04/09 Javascript
vue路由跳转传参数的方法
2019/05/06 Javascript
在Vue中使用icon 字体图标的方法
2019/06/14 Javascript
Nodejs在局域网配置https访问的实现方法
2020/10/17 NodeJs
ant design vue嵌套表格及表格内部编辑的用法说明
2020/10/28 Javascript
three.js中多线程的使用及性能测试详解
2021/01/07 Javascript
[02:43]2018DOTA2亚洲邀请赛主赛事首日TOP5
2018/04/04 DOTA
python服务器端收发请求的实现代码
2014/09/29 Python
Python Web框架Flask中使用新浪SAE云存储实例
2015/02/08 Python
python统计文本字符串里单词出现频率的方法
2015/05/26 Python
详解python--模拟轮盘抽奖游戏
2019/04/12 Python
Puppeteer使用示例详解
2019/06/20 Python
python笔记之mean()函数实现求取均值的功能代码
2019/07/05 Python
利用HTML5的新特点实现图片文件异步上传
2014/05/29 HTML / CSS
外企测试工程师面试题
2015/02/01 面试题
学生自我鉴定范文
2013/10/04 职场文书
生产经理的自我评价分享
2013/11/07 职场文书
人力资源部经理岗位职责规定
2014/02/23 职场文书
《分一分》教学反思
2014/04/13 职场文书
企业工会工作总结2015
2015/05/13 职场文书
周一给客户的问候语
2015/11/10 职场文书
学会掌握自己命运的十条黄金法则:
2019/08/08 职场文书
基于python制作简易版学生信息管理系统
2021/04/20 Python