JavaScript中声明和赋值的顺序

1,先有鸡还是先有蛋

    直觉上会认为JavaScript代码在执行时是由上到下一行一行执行的,但实际上这并不完全正确,有一种特殊情况会导致这个假设是错误的。

    考虑如下代码:

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

    你认为console.log(...)声明会输出什么?

    很多开发会认为是undifined,因为var a 声明在 a =2 之后,他们自然而然的认为变量被重新赋值了,因此会被赋予默认值undifined。但是,真正的输出结果是2.

    考虑另外一段代码:

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

    鉴于上一个代码片段所表现出来的某种非自上而下的行为特点,你可能会认为这个代码片段也会有同样的行为而输出2.还有人可能认为,由于变量a在使用前没有先进行声明,因此会抛出Referenceerror异常。

    不幸的是两种猜测都是不对的。输出来的会是undefined。


    那么到底发生了声明?看起来我们面对是一个先有鸡还是先有蛋的问题。到底是声明(蛋)在前,还是赋值(鸡)在前?

2,再谈编译器

    为了搞明白这个问题,我们需要回顾一下第一章中关于编译器的内容。回忆一下,引擎会在解释JavaScript代码之前首先对齐进行编译。编译阶段中的一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来。

    因此,正确的思考思路是,包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理。

    当你看到var a=2;时,可能会认为这是一个声明。但JavaScript实际上会将其看成两个声明: var a  和 a =2;.第一个声明是在编译阶段进行的。第二个赋值声明会被留在原地等待执行阶段。

    所以,我们第一个代码段会以如下形式进行处理:

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

     其中第一部分是编译,第二部分是执行。

    类似的,我们第二个片段实际上是按照以下流程处理的:
    
var a;
console.log(a);
a = 2;

    因此,打个比方,这个过程就好像变量和函数声明从它们在代码中出现的位置被"移动"到了最上面。这个过程叫做提升。

    只有声明本身会被提升,而赋值或其他运行逻辑会留在原地。如果提升改变了代码执行的顺序,会造成非常严重的破坏。

看下面一段代码:

foo();

function foo(){
	console.log(a); //undefined
	var a =2;
}

    foo的函数声明(这个例子还包括实际函数的隐含值)被提升了,因此第一行中的调用可以正常执行。

    另外值得注意的是,每个作用域都会进行提升操作。经过前面大部分的代码已经简化了(因为它们只包含全局作用域),而我们正在讨论的foo(...)函数自身也会在内部对var a进行提升(显然不是提升到了程序的最上方)。因此这段代码实际上会被理解为下面的形式:

function foo(){
	var a;
	console.log(a);
	a =2;
}
foo();

    可以看到,函数声明会被提升,但是函数表达式却不会被提升。

foo(); //不是ReferenceError,而是TypeError!

var foo = function bar(){
	...
}

    这段代码中的变量标识符foo()被提升并分配给所在作用域,因此foo()不会导致ReferenceError。但是foo此时并没有被赋值(如果它是一个函数声明而不是函数表达式,那么就会被赋值)。foo()由于对undefined值进行函数调用而导致非法操作,因此抛出TypeError异常。

    同时也要记住,即使是具名的函数表达式,名称标识符在赋值之前也无法在所在作用域中使用:

foo(); //TypeError
bar(); //ReferenceError

var foo = function bar(){
	//...
}

    这个代码片段经过提升后,实际上会被理解为以下形式:

var foo;
foo(); //TypeError
bar(); //ReferenceError
foo = function(){
	var bar = ...self...
	//...
}

3,函数优先

    函数声明和变量声明都会被提升。但是一个值得注意的细节是函数会首先被提升,然后才是变量。

       本篇文章摘自《你不知道的JavaScript》,相当于学习笔记,不过大部分是摘自上面的,若有侵权,联系删除.. (看上面写的在社区里也可以找到这些,不过我没找到...)

猜你喜欢

转载自blog.csdn.net/qq_39263663/article/details/80710095