Javascript中的变量提升/函数提升

138 阅读3分钟

废话

建议直接跳过

这是初学之后整理出来的一些笔记,在写之前,也看了很多大佬写的关于变量提升的笔记,在这里附上对我很有帮助的一篇文章(传送门),希望也可以帮助到正在看的你们呀!!!

随着不断学习不乱加深理解,会不断更新此笔记

变量提升/函数提升

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,这个方法函数声明不会被提升

那变量提升到底是怎么回事?

这里涉及到的知识点:执行上下文之变量对象和具体参考.

在我的初步理解是:

在一段代码被执行时会创建对应的执行上下文,一个执行上下文的生命周期分为创建执行两个阶段:

变量对象的创建,经历以下过程:

  1. 建立arguments对象。检查当前上下文中的参数,建立该对象下的属性与属性值。

  2. 检查当前上下文的函数声明,也就是使用function关键字声明的函数。在变量对象中以函数名建立一个属性,属性值为指向该函数所在内存地址的引用。如果函数名的属性已经存在,那么该属性将会被新的引用所覆盖。(常说的函数优先被提升, 且同名会产生覆盖)

  3. 检查当前上下文中的变量声明,每找到一个变量声明,就在变量对象中以变量名建立一个属性,属性值为undefined。如果该变量名的属性已经存在,为了防止同名的函数被修改为undefined,则会 直接跳过。

看下面的栗子:

function fun () {}
var fun = 'javascript'
console.log(fun);

// 'javascript'

在创建阶段:javascript引擎先将函数fun提升到对象变量(VO)中,创建一个fun属性,属性值是指向该函数的内存地址的引用,然后再将变量fun提升到对象变量中,因为存在同名函数,所以跳过undefined的赋值。(这里没有弄明白的是提升后只存在一个fun属性,还是两个同名属性,目前先按只存在一个属性理解的,等我弄明白了再更新)

变量对象里的属性只可读不可改

然后进入到执行阶段:变量对象变成活动对象(AO),开始赋值,执行代码。将属性fun的属性值变为javascript,这样在控制台打印时出现的就是javascript

活动对象的属性值可以改变。

大概就是这样的笔记了,继续学习,继续进步吧。