再理解—JavaScript的变量提升

学习过前端的同学们应该都对变量提升的概念不陌生,这对于没有接触过JavaScript开发的同学来说是一种极其反常识的现象。当时对这种现象并没有什么理解,只是了解并记住了这种现象。到了今天,我想重新描述我的理解,当然,未必准确,纯当抛砖引玉。

首先来看一段代码:

console.log(test)
var test = 'Hello world'
foo()
function foo(){
    console.log('test')
}

按照我当初初学时的理解,这段代码必然会报错啊,怎么能够在变量声明之前就使用变量呢?函数也是一样的。可是实际情况却是foo函数输出了test,而第一行的console.log则输出了undefined

这个结果说明了两个结论,一是变量或者函数是能够在被声明之前就被使用,二是未声明的变量的值是undefined

怎样来理解这两个结论呢?首先从行为层面来分析,我们可以将var test = 'Hello world'这个语句拆分成两部分,一部分是var test = undefined,另一部分是test = 'Hello World',也可以管第一个部分叫声明,第二个部分叫赋值。

那么上面的代码我们可以重新写为:

var test = undefined
function foo(){
    console.log('test')
}
console.log(test)
test = 'Hello world'
foo()

这就是按照传统理解重新组织的代码,当然我们可以这样来理解,但事实却并不是这样的,代码在执行过程中并不会被这样重新组织。但是却有一个类似的过程。

JavaScript代码在执行之前也是需要编译的,那么一段代码经过编译之后会生成执行上下文可执行代码两个部分。而在执行上下文之中有一个变量环境(Variable Environment)的对象,这个对象里就存储变量提升的内容。

接下来分析一下最上面的代码是如何生成变量环境对象的:

首先第一、三行代码不是声明语句,JavaScript引擎不会做任何处理。

第二行是声明语句,于是JavaScript引擎会在变量环境对象中新建一个test的属性,并使用undefined对其初始化。

第四行是一个函数声明,JavaScript引擎会将函数的定义存到堆中,然后在变量环境对象中新建一个foo属性,然后该属性存储函数定义在堆中的位置。

以上所说的过程是在编译过程中完成的,接下来看执行过程

执行到第一行时,JavaScript引擎会在变量环境对象中寻找test属性,此时对象中存在一个test属性且其值为undefined

执行到第二行,此时便会去更新变量环境对象中test的值为Hello world

执行到第三行,JavaScript引擎就会在变量环境对象中查找foo这个函数,由于对象中存在该函数的引用,于是便执行函数,输出test。


可能有人会有困惑,如果出现了两个名称相同的变量或函数怎么办?例如:

function foo(){
    console.log('test')
}
foo()

function foo(){
    console.log('hello world')
}
foo()

这段代码执行的结果是输出两行hello,world。原因也很好理解,在编译过程中,JavaScript引擎先发现第一个foo函数,会将其定义存到堆中,而发现第二个foo函数时也会如法炮制,这样的结果,就是第一个函数在变量环境对象中的定义被第二个覆盖,于是执行的结果便都是第二个函数的结果了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值