JavaScript中的变量提升本质
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错误,难道let和const声明的变量没有被“提升”吗?
事实上所有的声明(function, var, let, const, class)都会被“提升”。但是只有使用var关键字声明的变量才会被初始化undefined值,而let和const声明的变量则不会被初始化值。
只有在执行阶段JavaScript引擎在遇到他们的词法绑定(赋值)时,他们才会被初始化。这意味着在JavaScript引擎在声明变量之前,无法访问该变量。这就是我们所说的Temporal Dead Zone,即变量创建和初始化之间的时间跨度,它们无法访问。
如果JavaScript引擎在let和const变量被声明的地方还找不到值的话,就会被赋值为undefined或者返回一个错误(const的情况下)。
举例:
let a
console.log(a) // undefined
a = 5
在编译阶段,JavaScript引擎遇到变量a并将它存到词法环境中,但因为使用let关键字声明的,JavaScript引擎并不会为它初始化值,所以在编译阶段,此刻的词法环境像这样:
lexicalEnvironment = {
a: <uninitialized>
}
如果我们要在变量声明之前使用变量,JavaScript引擎会从词法环境中获取变量的值,但是变量此时还是uninitialized状态,所以会返回一个错误ReferenceError。
在执行阶段,当JavaScript引擎执行到变量被声明的时候,如果声明了变量并赋值,会更新词法环境中的值,如果只是声明了变量没有被赋值,那么JavaScript引擎会给变量赋值为undefined。
tips: 我们可以在let和const声明之前使用他们,只要代码不是在变量声明之前执行:
function foo() {
console.log(name)
}
let name = 'John Doe'
foo() // 'John Doe'
Class提升
同let和const一样,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中的变量提升本质的更多相关文章
- 简单谈一谈JavaScript中的变量提升的问题
1,随笔由来 第一天开通博客,用于监督自己学习以及分享一点点浅见,不出意外的话,应该是一周一更或者一周两更. 此博客所写内容主要为前端工作中遇上的一些问题以及常见问题,在此基础上略微发表自己的一点浅 ...
- 谈谈javascript中的变量提升还有函数提升
在很多面试题中,经常会看到关于变量提升,还有函数提升的题目,所以我就写一篇自己理解之后的随笔,方便之后的查阅和复习. 首先举个例子 foo();//undefined function foo(){ ...
- JavaScript中的变量提升和函数提升
在EcmaScript5中只有全局作用域和函数作用域,EcmaScript6增加了块级作用域. 块级作用域(一对花括号{}即为一个块级作用域) 变量提升 console.log(name); //un ...
- JavaScript中的变量提升和严格模式
1.什么是变量提升 所谓的变量提升指的是:函数声明和变量声明总是会被解释器悄悄地被"提升"到方法体(作用域)的最顶部. //先声明后使用 var x; console.log(x) ...
- 在javascript中关于变量与函数的提升
在javascript中关于变量与函数的提升 一.简介 在javascript中声明变量与函数的执行步骤: 1.先预解析变量或函数声明代码,会把用var声明的变量或者函数声明的代码块进行提升操作 2. ...
- JavaScript 中定义变量时有无var声明的区别
关于JavaScript中定义变量时有无var声明的区别 var a=5; //正确 a=5; //正确 在javascript中,以上两种方法都是定义变量的正确方法.微软的Script56.CHM中 ...
- JavaScript学习系列2一JavaScript中的变量作用域
在写这篇文章之前,再次提醒一下 JavaScript 是大小写敏感的语言 // 'test', 'Test', 'TeSt' , 'TEST' 是4个不同的变量名 JavaScript中的变量,最重要 ...
- JavaScript 中的变量命名方法
三种命名方法 在程序语言中,通常使用的变量命名方法有三种:骆驼命名法(CamelCase),帕斯卡命名法(PascalCase)和匈牙利命名法. 依靠单词的大小写拼写复合词的做法,叫做"骆驼 ...
- (转载)JavaScript中定义变量
(转载)http://blog.163.com/xuxiaoqianhz@126/blog/static/165190577201061594421870/ JavaScript中定义变量有两种方式: ...
- 关于Javascript中声明变量、函数的笔记
一.概念 1.变量声明 在JavaScript中,变量一般通过var关键字(隐式声明,let关键字声明除外)进行声明,如下通过var关键字声明a,b,c三个变量(并给其中的a赋值): var a=1, ...
随机推荐
- 适用于AbpBoilerplate的RocketChat Api库
RocketChat 适用于AbpBoilerplate的RocketChat Api库 Rocket.Chat 是一个免费.开源.可扩展.高度可定制且安全的平台,可让您与团队进行交流和协作.共享文件 ...
- 第143篇:手写vue-router,实现router-view
好家伙, 今天来手写我们的老伙计vue-router, 1.替换router 新开一个项目,并使用我们手写的router 2.大致结构 let Vue; // 保存vue的构造函数 cla ...
- springboot实现post请求
找了一堆,发现还是这个靠谱 package com.qishiyun.poplar.qlib.util; import cn.hutool.json.JSONUtil; import com.alib ...
- 视野修炼第71期 | Rspack 家族新成员 Rsdoctor
欢迎来到第 71 期的[视野修炼 - 技术周刊],下面是本期的精选内容简 强烈推荐 Rspack 新成员:Rsdoctor Bun Shell DCloud:App跨平台框架对比2023版 开源工具& ...
- 使用nodejs从控制台读入内容
在写算法题的时候,基本上都需要输入输出语句,在大多数练题网站上当想用js书写算法题时,发现不知道怎么输入,其实Node是提供了一个readline模块来实现此功能的 tip 笔者用过的练题网站只有le ...
- 直播预约 | 邀您共同探讨“云XR技术如何改变元宇宙的虚拟体验”
随着数字化时代的到来,元宇宙成为了人们关注的焦点.它是一个虚拟的世界,融合了现实与虚拟的元素,让人们可以以全新的方式进行交互.创作和体验. 云XR技术是元宇宙建设的重要支撑技术之一,元宇宙需要具备高度 ...
- Linux快速入门(八)效率工具(SSH)
环境 (1)Kali(源主机),IP:10.211.55.4/24 (2)Ubuntu(目标主机),IP:10.211.55.5/24 SSH OpenSSH用于在远程系统上安全的运行Shell,假设 ...
- 记录--ECharts — 饼图相关功能点(内环、外环、环形间隔、环形文字、轮播动画)
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 记录一下在公司遇到的一些功能,以及相关实现 以上的内容我花了一周时间去实现的,自己也觉得时间很长,但主要因为很少使用ECharts,导致使 ...
- Unity中文字体获取
Unity对中文字体支持较差,这里给出了几个可以使用的中文字体下载网站 后续会更新如何使用: 51Font -「免费字体发布平台」为您第一时间发布商用免费字体开源字体 (17font.com) fre ...
- KingbaseES V8R3集群运维案例之---备库状态‘down’修复
案例说明: Kingbase V8R3集群,集群启动正常,备库数据库服务正常,流复制状态正常.但是备库在show pool_nodes下查看是'down'状态,通过pcp_attach_node重 ...