在一个阳光明媚的早晨,Y同学拿着手里的早餐——鸡蛋不禁想起一个问题,先有鸡还是先有蛋呢?于是和C同学讨论起来这个问题,双方各执一词。这时候W同学过来说:不如以最近学的JavaScript代码中变量的声明和赋值问题一决胜负吧!
Y同学随手敲了下面的代码:
a = 2;
var a;
console.log(a);
猜猜console.log会输出什么呢?
Y同学:这里输出的是undefined
,JavaScript代码在执行上是按照由上到下一行一行去执行的,自然而然var a;
重新把a赋值了,因此会输出undefined
。
C同学:我认为会输出2,因为var会进行变量提升,因为在代码执行前是要预编译的。
Y同学:我不听我不听,拿代码来说服我。
C同学:那你看这段代码会输出什么呢?
console.log(a);
var a = 2;
Y同学:你先说吧,我思考下(心里偷偷想,既然你说了var会变量提升,那一定输出2了,哈哈哈)
这时候有同学看到了,直接说,在严格模式下,变量a没有先进行声明,因此会抛出ReferenceRrror异常。
C同学:我认为会输出undefined
。(暗自窃喜,我赢定了…)
Y同学:你刚刚不是说var可以变量提升,怎么现在反悔了(噘嘴)?
W同学:那咱们就一起来看看是怎么回事吧!
小黑板:首先我们得知道JavaScript事实上是一门编译语言,它的编译原理和传统的编译语言非常相似。在传统的编译语言的流程中,程序中的一段源代码在执行前会经历三个步骤:
- 分词/词法分析
- 解析/语法分析
- 代码生成**
(具体解释下回分解,本次直接对题进行分析)——(瓜子不够了)
在我们看到var a = 2;这句代码中,可能会认为这是一个声明,但JavaScript实际上会解析为两句代码var a; a =2;第一句是在编译阶段进行的,第二句会原地等待执行阶段的到来。Y同学写的代码实质上是这样的:
var a;
a = 2;
console.log(a);
同样C同学的第二段代码实质上是这样的:
var a;
console.log(a);
a = 2;
在这里就发生了变量提升,对于变量而言,那就是先有声明才有赋值。(提升的定义:无论作用域中的声明出现在什么地方,都将在代码本身被执行前首先进行处理,可以将这个过程形象地想象成所有的声明(变量和函数)都会被“移动”到各自作用域的最顶端,这个过程被称为提升。)
C同学:那就是先有蛋才有鸡了,哈哈哈。
W同学:敲了敲黑板,平时我们在写代码的过程中,要注意的是:
- 只有声明本身才会被提升,赋值以及其他逻辑会留在原地,如果提升改变了代码执行的顺序,会造成严重的破坏;
- 而且函数声明也会被提升,重点是函数会首先被提升,然后才是变量。
- 在声明时注意避免重复声明,特别是普通的var声明和函数声明混合在一起的时候,否则大家就是上班写bug,下班改bug。
本次battle C同学获得胜利,奖励蜜雪冰城一杯(撒花~)。