2、变量提升的原理

问题:以下代码会输出什么?

showName()
console.log(myname)
var myname = 'jack'
function showName() {
    console.log('函数showName被执行');
}
console.log(myname)

如果要了解为什么会存在变量提升就需要先了解下变量存在哪里,提升是什么意思?
答案是:代码在编译阶段,变量和函数会被存放到变量环境中,变量的默认值会被设置为 undefined;在代码执行阶段,JavaScript 引擎会从变量环境中去查找自定义的变量和函数。(就是存在变量环境中的意思,继续变量环境是啥)

首先javascript代码的执行过程是什么样的呢?一段 JavaScript 代码在执行之前需要被 JavaScript 引擎编译,编译完成之后,才会进入执行阶段。意思就是分两个阶段:编译,编译之后生个什么东西,执行

3.png

编译阶段

从上图可以看,经过编译后,会生成两部分内容:执行上下文(Execution context)和可执行代码

执行上下文是 :JavaScript 执行一段代码时的运行环境。比如调用一个函数,就会进入这个函数的执行上下文,在这个阶段中,执行上下文会分别创建变量对象,建立作用域链,以及确定this指向。

上下文.png

以上就说明:先编译生成执行上下文,执行上下文中有变量对象,变量就存在这个变量对象中

一、我们可以一行一行来分析代码,看看编译过程。

showName()
console.log(myname)
var myname = 'jack'
function showName() {
    console.log('函数showName被执行');
}
console.log(myname)

第 1 行和第 2 行,由于这两行代码不是声明操作,所以 JavaScript 引擎不会做任何处理;
第 3 行,由于这行是经过 var 声明的,因此 JavaScript 引擎将在环境对象中创建一个名为 myname 的属性,并使用 undefined 对其初始化;
第 4 行,JavaScript 引擎发现了一个通过 function 定义的函数,所以它将函数定义存储到堆 (HEAP)中,并在环境对象中创建一个 showName 的属性,然后将该属性值指向堆中函数的位置。如果变量与函数同名,则在这个阶段,以函数值为准。

经过编译阶段变量对象中是这样的:

// VO 为 Variable Object的缩写,即变量对象
VO = {
    myname : undefined,
   showName : <showName reference>  // 表示showName 的地址引用
}

执行阶段:

JavaScript 引擎开始执行“可执行代码”,按照顺序一行一行地执行。

showName()
console.log(myname)
var myname = 'jack'
function showName() {
    console.log('函数showName被执行');
}
console.log(myname)

我们可以一行一行来分析上述代码:(执行阶段):

第 1 行,调用函数showName能够在变量对象中找到 ,输出 '函数showName被执行';
第 2 行,查找到myname,根据编译阶段的结果,输出 undefined;
第 3行, 将myname 赋值为jack;
第 4-6行,这就是函数声明
第7行,查找到myname,经过第三行的操作,输出 'jack';

// 执行阶段
VO ->  AO   // Active Object
AO = {
    showName : <showName reference>,
    myname : 'jack',
    this: Window
}

练习:

    console.log(foo());
    function foo() {
        return 2;
    }
    var a;
    console.log(a);
    a = 1;
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • JavaScript机制 [toc] 变量提升(Hoisting) 看代码的执行效果 结果 结论 在执行过程中,若...
    刘佳阔阅读 305评论 0 0
  • js'一段'代码执行前,需要先编译,编译后会生成两部分内容:执行上下文和可执行代码:执行上下文:比如调用一个函数,...
    sisselxie阅读 183评论 0 0
  • [toc] 示例代码 仅改变了a中name的属性值,但是最终a和b打印出来的值都被改变了。像是ab都引用了 同样的...
    刘佳阔阅读 367评论 0 0
  • 栈空间和堆空间:数据是如何存储的? JavaScript 是什么类型的语言把这种在使用之前就需要确认其变量数据类型...
    欢欣的膜笛阅读 342评论 0 1
  • 一、变量提升是什么? 1.1 一个变量提升的例子 执行结果如下: 可以看到,在声明变量前打印变量,打印出的是 un...
    笑飞阅读 5,518评论 0 0