变量提升
在js中我们用var声明的变量是存在变量提升的。换句话说,我们js的解释器在解释js代码的时候,会优先把所有的变量声明提到前面。
示例代码
var的变量提升
下面我演示的就是一个简单的变量提升的问题。
js源代码
console.log(a)
var a=1
console.log(a)
js解释器编译的顺序:
var a;
console.log(a)
a=1
console.log(a)
这里理解的要点是,js只是把变量的声明提前了。但是赋值并没有提前。var a=1其实是两行代码的简写,var a;a=1
function变量赋值提升
接下来这个问题可是经典的面试题
function foo(a){
console.log(a)
var a=2
function a(){
}
console.log(a)
}
foo(10)
请问两次的console.log分别打印出什么呢?
想要搞清楚这个问题,我们需要理解变量提升的优先级。 其实在JS中,被变量提升的不仅仅有var还有我们的function,而且function提升变量的优先级要比var要高一些,而且这个函数变量提升还是变量和赋值同时提升!!!
所以上面这段代码在js解释器下是按照这样的顺序解释的
function foo(a){
var a=function (){
}
console.log(a)
a=2
console.log(a)
}
foo(10)
虽然我们调用foo函数时候传递了一个10进去,但是根据js的作用域链规则,js会优先在最小的作用域依次,向上、向外去寻找声明的变量。显然这个时候我在外面传的10就没有作用了,因为js在向上找的同时在{}里面找到了变量a的声明,也就是var a=function(),就没有必要向外找传递进来的10了
所以第一个打印语句打印的是函数本体,第二个打印的是2
理解上面代码的要点是理解function声明函数其实是变量和赋值同时提升,这里和我们的var是不一样的,var仅仅是声明提升,它的赋值不会提升,所以才有可能打印出undefined(undefined就是声明了但是却没有赋值的意思)
局部变量的偷偷赋值
我们看下下面案例的输出
function foo(a) {
var a
console.log(a)
}
foo(10)
输出结果是10
奇怪了这是为什么呢?a我们没有赋值呀,根据作用域链规则,应该是undefined呀。为什么传递进去的10,却打印出来了。
其实这里的底层是这样的
function foo(var a=10) {
var a
console.log(a)
}
foo(10)
我们在console.log(a)时候,js沿着作用域链在括号内寻找,找到了a,发现是undefined,但是js不甘心,继续沿着作用域链向上检索,终于搜寻到外面的形参声明赋值,然后输出10 也就是说作用域链向上查找不是查到声明就完的,如果js发现它是undefined的话还会继续向上找
我们再来一道题练习一下作用域链
var a=10
var a=2
{
var a
console.log(a)
}
输出2,不是undifined,js找到undifined是不会甘心的,会继续向上找不是undifined的数值,找到了一个不是undifined就不继续找了
再来看一个有趣的事情
function foo(a){
console.log(a)
var a=2
console.log(a)
}
foo(10)
这个我们来看js编译之后的执行顺序
function foo(var a=10){
console.log(a)
a=2
console.log(a)
}
foo(10)
显然输出10和2
箭头函数和function不一样
function foo(a) {
console.log(a)
a = () => {
}
var a = 2
console.log(a)
}
foo(10)
输出什么呢?
我们来分析一下js编译之后的执行顺序
function foo(var a=10) {
var a
console.log(a)
a = () => {
}
a = 2
console.log(a)
}
foo(10)
输出10和2
这里注意的是我们的箭头函数和function是不一样的,上面说我们的function是变量声明提升,赋值也会提升,但是我们的箭头函数仅仅只会变量提升而已,因为()=>function关键字是不一样的,function是声明函数的关键字,()=>只是一个赋值的右值而已
回过头来再看这个例子
function foo(a) {
console.log(a)
function a (){
}
var a = 2
console.log(a)
}
foo(10)
它输出的是function()和2
js编译后的执行顺序如下
function foo(var a=10) {
var a = function (){
}
console.log(a)
var a = 2
console.log(a)
}
foo(10)
好了,相信通过我的讲解,大家应该对变量提升有了新的认识了。我们下次再见,see you!
|