废话
建议直接跳过
这是初学之后整理出来的一些笔记,在写之前,也看了很多大佬写的关于变量提升的笔记,在这里附上对我很有帮助的一篇文章(传送门),希望也可以帮助到正在看的你们呀!!!
随着不断学习不乱加深理解,会不断更新此笔记
变量提升/函数提升
1.变量提升
先看一个栗子:
(function () {
console.log(x);
var x = 'javascript';
})();
//undefined
上面的栗子在控制台查看并不会报错,而是输出undefined
,这就涉及到变量提升的问题,实际操作代码是下面的样子:
(function () {
var x ;
console.log(x);
x = 'javascript';
})();
无论变量的声明在哪个地方,javascript引擎都会在代码被执行前将变量的声明提前处理,可以简单地认为这些声明被移动到了代码的最顶端,这就是提升过程。
但要注意以下的栗子并不涉及变量提升,只是代码在操作时,因为同名而产生的覆盖:
var x = function() {};
x= 'javascript';
console.log('x的值为:' + x);
//x的值为:javascript
2.函数提升
函数被优先提升,才会提升变量。
该注意的是以下两种函数定义的方式,容易造成混淆:
//函数声明式
(function () {
f();
function f() {
console.log('这是函数声明式')
}
})();
这个方法在控制台的输出是:这是函数声明式
,无报错,函数声明被提升了。
//函数表达式
(function () {
f();
var f = function() {
console.log('这是函数表达式')
};
})();
这个方法在操作台报错:TypeError: f is not a function
,这个方法函数声明不会被提升
那变量提升到底是怎么回事?
这里涉及到的知识点:执行上下文之变量对象和具体参考.
在我的初步理解是:
在一段代码被执行时会创建对应的执行上下文,一个执行上下文的生命周期分为创建和执行两个阶段:

变量对象的创建,经历以下过程:
-
建立arguments对象。检查当前上下文中的参数,建立该对象下的属性与属性值。
-
检查当前上下文的函数声明,也就是使用
function
关键字声明的函数。在变量对象中以函数名建立一个属性,属性值为指向该函数所在内存地址的引用。如果函数名的属性已经存在,那么该属性将会被新的引用所覆盖。(常说的函数优先被提升, 且同名会产生覆盖) -
检查当前上下文中的变量声明,每找到一个变量声明,就在变量对象中以变量名建立一个属性,属性值为
undefined
。如果该变量名的属性已经存在,为了防止同名的函数被修改为undefined
,则会 直接跳过。
看下面的栗子:
function fun () {}
var fun = 'javascript'
console.log(fun);
// 'javascript'
在创建阶段:javascript引擎先将函数fun
提升到对象变量(VO)中,创建一个fun
属性,属性值是指向该函数的内存地址的引用,然后再将变量fun
提升到对象变量中,因为存在同名函数,所以跳过undefined
的赋值。(这里没有弄明白的是提升后只存在一个fun
属性,还是两个同名属性,目前先按只存在一个属性理解的,等我弄明白了再更新)
变量对象里的属性只可读不可改。
然后进入到执行阶段:变量对象变成活动对象(AO),开始赋值,执行代码。将属性fun
的属性值变为javascript
,这样在控制台打印时出现的就是javascript
。
活动对象的属性值可以改变。
大概就是这样的笔记了,继续学习,继续进步吧。