# 前言
当JavaScript代码执行的时候,会出现变量提升的情况。
让我们来看一段代码~
logName()
console.log(name)
var name = 'mobs'
function logName() {
console.log('执行logName函数');
}
1
2
3
4
5
6
2
3
4
5
6
惯性去思考🤔,代码应该是按顺序去执行:
- 第一行去执行logName函数,但是发现还没有关于logName函数的定义,执行会报错
- 第二行去打印name变量,但发现还没有name的定义,执行会报错
但是实际这段JavaScript代码执行的结果是:
> "执行logName函数"
> undefined
1
2
2
可以看出:
- 变量在定义之前使用,不会报错,但该变量的值会被赋值为undefined,并非其定义时的值。
- 函数在定义之前使用,不会报错,并且能正确的执行。 所以为啥能在定义之前去使用呢?需要知道变量提升。
# 变量提升(Hoist)
# 定义
变量提升是指,JavaScript代码在执行的时候,JavaScript引擎会把变量的声明、函数的声明的这些代码,提升到整个代码的开头。当变量被提升,会给变量设置默认值undefined。
# JavaScript中的声明和赋值
var name = 'mobs'
1
我们可以拆解一下:
// 声明
var name
// 赋值
name = 'mobs'
1
2
3
4
2
3
4
继续看下函数的声明和赋值
// 函数声明
function test(){
console.log('test')
}
// ---------------
var test1 = function(){
console.log('test1')
}
// 拆解如下↓↓↓↓↓↓↓↓
// 声明
var test1 = undefined
// 赋值
test1 = function(){
console.log('test1')
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# JavaScript引擎如何处理相同函数名如何处理?
如果定义了两个相同名字的函数,生效的是最后一个定义的函数。
# 纵观JavaScript代码执行的流程
“变量提升”是JavaScript代码执行过程中的一个行为,变量和函数的声明的代码看上去
会被移动到代码的最前面。但是实际上变量、函数声明的代码所在的位置并不会真的去改变,仅仅是在编译阶段被JavaScript引擎放到了内存中。
概括代码流程:
代码 => 编译 => 执行
# 编译
代码编译后产生:
- 执行上下文(Execution context)
- 可执行代码(字节码)
执行上下文就是JavaScript代码运行的环境(抽象理解要记住),函数的调用就会产生一个执行上下文,代码执行就会进入执行上下文。
执行上下文包含的信息:
- 变量对象(变量环境) => 这个对象里面就保存着变量提升的内容函数定义会被存储到堆(Heap)中,变量对象test属性会指向堆中的函数。
变量对象: { name: undefined, test: function() { console.log('test') } }
1
2
3
4 - 作用域链(词法环境)
- this(动态环境)
对于声明以外的代码,JavaScript引擎会将其编译为字节码。
# 执行
JavaScript引擎配合执行上下文开始按照顺序执行可执行代码(字节码)。
# 总结
- JavaScript代码执行的时候,需要先编译、再执行,编译时会进行变量提升。
- 编译阶段,变量、函数的声明会被保存到执行上下文的变量对象中。
- 执行阶段,JavaScript配合执行上下文去执行代码。