JavaScript 之变量提升详解
#Js 变量提升#
一、解释:所谓JS “变量提升”,即变量可以在声明之前使用,值为undefined。
比如
a = 1;
var a;
console.log(a);
上述代码,如果按照自上而下的执行顺序的话,按理来说,应该输出 undefined,但是JavaScript 严格意义上并不是自上而下执行的语言。这段代码会输出1,因为存在变量提升,变量提升会将当前作用域声明的变量提升到程序顶部,因此,上述代码等价于=>
var a; a = 1; console.log(a);
二、赋值语句不会将变量声明提升
来看这个例子,
console.log(a); var a = 1;
上述代码会报出 undefined,因为变量声明会提升,而赋值语句则不会将变量提升。对于JS 来说,其实 var a = 1; 是分两步的,1. var a; 2. a = 2; 而Js 只会将第一步提升到顶部,所以上述代码等价于=>
var a; console.log(a); a = 1;
三、为什么会有变量提升?
JS 和其他语言一样,都要经历编译和执行阶段,而JS 在编译阶段的时候,会搜集所有变量的声明并且提前声明变量,而其他语句则不会改变他们的顺序,因此,在编译阶段的时候,第一步就已经执行了,而第二步则是在执行阶段执行到该语句的时候才执行。
用 var 声明的变量才存在变量提升问题,而ES6 中使用 let 则不会有该问题。
函数声明和其他声明一起出现的时候,就可能引起一些困扰。
foo(); function foo() { console.log('foo'); } var foo = 2;
上述代码会输出 foo呢?还是报错呢?
答案是输出 foo,因为函数声明和其他声明一起出现时,函数声明高于一切,函数是JS 的一等公民,这里,foo() 是先调用,后面才有它函数的声明,但是也可以使用该函数,原因就在于 JS 的函数其实是先声明,后使用,类似函数提升。
声明相同名称的函数,以最后一个为准:
foo(); function foo() { console.log('1'); } function foo() { console.log('2'); }
上述代码,会打印出 2, 因为有多个同名函数声明的时候,后面的会覆盖前面的。
有了这么多案例,我们来看看下面这个问题:
foo(); var foo = function() { console.log('foo'); }
上述代码会输出什么?会报错呢,还是输出 foo ? 答案是会报错,因为我们之前说过,变量的赋值没有变量提升的问题,所以上述代码类似于, 也就是说这里声明的是个foo变量,无法当函数用。
foo(); var foo; foo = function() { console.log('foo'); }
总结:
1.JS 使用 var 关键字声明的变量,会将变量提升到js 顶部执行,即变量提升,其实是因为JS 是先声明,后使用的,所有声明会在编译阶段先声明好。
2. 使用 var 关键字声明之后直接赋值,不存在变量提升。如 var a = 1; 赋值语句不存在变量提升,对于函数先声明变量在直接赋值也一样,不存在变量提升。
3.声明同名函数,后面的会覆盖前面的,多个同名函数同时声明,只看最后一个。