js执行之变量对象
一、变量对象是什么?
在学习执行上下文的知识点时,我们已经了解到js在执行时每次触发函数执行都会生成一个上下文来保证函数的执行顺序,那么什么是变量对象?变量对象则是保证js读取变量的顺序以及变量调用的时机,这么说可能不好理解,我们还需要了解在创建执行上下文的同时还做了哪些事。
二、执行上下文的过程
1.执行上下文的生命周期
每次执行上下文都在函数调用的时候创建,那么函数的执行上下文可以分为两个生命周期:
创建阶段: 即在函数刚开始调用的时候,这时会依次创建变量对象,确定作用域链,同时确定this指向。
执行阶段:函数执行的过程中,会完成变量赋值,函数引用,以及其他代码的依次执行
该博客主要记录变量对象的相关知识,也相当于自己复习一遍,方便未来回过头来复习,其他知识暂时不做过多叙述,有空再写(狗头.jpg)
2.变量对象
变量对象是指执行上下文的变量对象,它无法被显示的访问到,但是确实有这个概念,它决定了变量该如何赋值如何引用,首先我们以创建一个简单的对象为例子:
function getName(age, name) {
var a = 6
var b = 7
function getAge(age) {
return age
}
console.log(a,b)
}
getName(1, '张三')
1: 第一步,在上下文执行过程中,首先会创建arguments对象,即遍历当前函数的所有参数,属性名和属性值一一对应,比如上述例子,会创建一个如此的arguments对象,并将其放入变量对象中
/* arguments对象是一个类数组对象,但是只有length属性和索引下标,无法调用其他数组方法,可以用Array.of或者Array.from转数组
*/
Arguments(2) [1, "张三"]
2: 第二步,检查当前上下文中的函数声明,也就是使用function关键字定义的函数,在变量对象中以function后跟的函数名为键名,该函数的内存引用为键值。
{
getAge: (age) => {
return age
}
}
3: 第三步,寻找当前上下文的变量声明,每找到一个变量声明就在变量对象中以变量名作为键名,键值就赋值为underfined
{
getAge: (age) => {
return age
},
a: underfined,
b: underfined
}
4:第四步,顺序执行当前上下文的其他代码,直至上下文从栈中弹出
3.变量提升
现在我们已经了解了在上下文中如何完整的创建一个变量对象,而在JavaScript中还有一个很经典的变量提升,我们通过变量对象就能很容易的理解变量提升,先看下面这个例子
function test() {
console.log(b)
console.log(a)
function b() {
console.log(a)
}
b()
var a = 6
}
test()
我们来分析一下上面的代码,根据变量对象创建的过程,首先肯定是创建arguments对象,接着会找上下文中的函数声明b,所以b会先提前声明,之后才是找到变量声明a,所以代码其实会变成这样
function test() {
function b() {
console.log(a)
}
var a = underfined
console.log(b)
console.log(a)
b()
a = 6
}
test()
最后执行的结果就很显而易见了
ƒ b() {
console.log(a)
}
undefined
undefined
4.全局上下文的变量对象
之前我们所讨论的都是函数的变量对象。而除了函数上下文之外,还有个全局上下文,全局上下文的变量对象就是window对象,它是可访问的,全局默认创建的属性都在它上面,全局的this也是指向window对象。
5.let/const
let/const都是es6新增的定义变量的声明关键字,它们与var最关键的区别就在于它们有块级作用域,那么会不会影响到变量对象的创建呢,我们可以看看下面这个例子:
function test() {
console.log(a)
let a = 6
}
test()
这里按照变量对象创建的步骤,理应变成下面这样
function test() {
let a = underfined
console.log(a)
a = 6
}
test()
但实际上我们可以看一下打印结果
Uncaught ReferenceError: Cannot access ‘a’ before initialization
at test (test.html:13)
at test.html:17
这句话的大概意思是,不能在初始化之前访问a,其实用let/const定义的变量,它们也会声明提升,但是不会像var一样初始化underfined,所以在let/const定义变量之前调用会报这个错误,这个现象也叫做 暂时性死区,很好理解,即变量声明到赋值的中间,无法对变量进行访问。
总结
通过对变量对象的总结,我们能够更好的理解变量提升以及再往后的作用域链,this指向,所以理解变量对象还是比较重要的。还有就是为了避免变量提升带来的负面影响,在编写代码的时候尽量在前面定义变量。