yliu

时来天地皆同力,运去英雄不自由

变量提升


这里只是用伪代码的形式来说明,实际上变量声明只是执行上下文有关,推荐阅读 JavaScript深入之变量对象

太长不看篇

函数参数 > 函数声明 > 变量声明

变量声明

首先想用一个伪生命周期来说这个事情,假设这段代码分为两个阶段,初始化阶段和赋值阶段; 看下面一段代码,用伪系统的话来阐述

console.log(a);
var a = 10;

如果按照上面的声明周期来说,首先变量 a 会在作用域注册一个变量(如果没有)默认赋值为 undefined

初始化完成后,开始执行代码,第一行语句的时候因为变量 a 未经过赋值阶段,这一阶段的值是 ndefined,所以打印的结果自然也就是 undefined;

在第二行的时候变量 a 会经过赋值阶段,这时变量 a 的值就是 10 了。

函数声明

函数声明与变量声明规则基本一致,优先级比变量声明要高

是不是只说这一句话大家有些失望,如果只是单独来说函数声明未免太没意思,下面就结合变量声明来说说函数声明,毕竟代码只有变量声明就做不到有趣了。

a();
var a = 10;
function a() {
  console.log(5);
}

上面的执行结果是打印数字 5,为什么会出现这种情况呢?上面我们已经说了函数声明优先于变量声明,那么上面代码实际可以拆封成下面形式

function a() {
  // ...
}
a();
a = 10;

你可能还有疑惑,事实上如果变量提升的时候发现已经存在变量就会默默忽略掉,比如上面的代码变量 a 已经是一个函数了,那么变量声明的 a 会被忽略。

最后说下函数参数,参数也是变量的一种形式,它的优先级最高,但是同样会受到函数声明的影响

function a(x) {
  console.log(x);
  function x() {}
}
a(5);

这里输出结果是函数 x,原因是函数声明提升的时候会执行一个覆盖操作,就像我们写代码x = 5这样

最后

这里说的有很多地方不足,只是自己的见解,更推荐一篇文章10 分钟理解执行上下文

最后根据上面的内容讲解一下他布置的一到题目

console.log(x);
var x = 10;

console.log(x);
x = 20;

function x() {}
console.log(x);

if (true) {
  var a = 1;
} else {
  var b = true;
}

console.log(a);
console.log(b);

首先初始化阶段,function x 最先被提升,后面的变量提升因为已经存在函数 x 的原因会被忽略 第一个 console 输出的是函数 x

之后执行到第二行代码的时候 x 被改变变成 10,第二个 console 输出为 10,之后继续被赋值为 20,第三个 console 输出为 20

第四个和第五个 console 的输出分别为 1 undefined,这是因为 es5 的环境下并不存在块级作用域,变量 ab 会执行变量提升这一步骤, 不同的是 a 被赋值为了 1,而 b 因为没有执行到 var b = true 所以值还是 undefined