浅析JavaScript中的变量提升

 更新时间:2022年06月01日 11:54:22   作者:​ 哎嘿咬我呀   ​  
这篇文章主要介绍了浅析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错误,难道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变量提升内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 微信小程序列表中item左滑删除功能

    微信小程序列表中item左滑删除功能

    这篇文章主要介绍了微信小程序列表中item左滑删除功能,本文分步骤给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-11-11
  • JavaScript异步调用定时方法并停止该方法实现代码

    JavaScript异步调用定时方法并停止该方法实现代码

    JavaScript异步调用定时方法并停止该方法实现代码 ,需要的朋友可以参考下
    2012-03-03
  • js简单粗暴的发布订阅示例代码

    js简单粗暴的发布订阅示例代码

    这篇文章主要给大家介绍了js简单粗暴的发布订阅的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • JavaScript中的函数(二)

    JavaScript中的函数(二)

    函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。本文给大家介绍介绍javascript中的函数(二),对javascript函数相关知识感兴趣的朋友一起学习吧
    2015-12-12
  • JavaScript基础之流程控制语句的用法

    JavaScript基础之流程控制语句的用法

    下面就为大家带来一篇JavaScript基础之流程控制语句的用法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • JS实现json的序列化和反序列化功能示例

    JS实现json的序列化和反序列化功能示例

    这篇文章主要介绍了JS实现json的序列化和反序列化功能,结合具体实例形式分析了javascript针对json的序列化与反序列化相关实现技巧,需要的朋友可以参考下
    2017-06-06
  • layer.js open 隐藏滚动条的例子

    layer.js open 隐藏滚动条的例子

    今天小编就为大家分享一篇layer.js open 隐藏滚动条的例子,具有很好的参考价值,希望对大家有所帮助。 一起跟随小编过来看看吧
    2019-09-09
  • Echarts绘制气泡图的示例代码

    Echarts绘制气泡图的示例代码

    Echarts是一款基于JavaScript的数据可视化库,它提供了丰富的图表类型,本文将详细介绍如何使用Echarts来绘制气泡图,并介绍气泡图相关的配置,需要的可以参考下
    2023-12-12
  • 微信小程序嵌入H5页面(web-view)的方法详解

    微信小程序嵌入H5页面(web-view)的方法详解

    使用<web-view>标签能在小程序中打开外部网页,但是要打开的网页的域名必须跟小程序的业务域名(业务域名可以在小程序的后台管理界面添加)一致,否则在真机上是打不开的,下面这篇文章主要给大家介绍了关于微信小程序嵌入H5页面(web-view)的相关资料,需要的朋友可以参考下
    2022-09-09
  • js中document.referrer实现移动端返回上一页

    js中document.referrer实现移动端返回上一页

    本文主要介绍了document.referrer实现移动端返回上一页的方法,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02

最新评论