JS中作用域和变量提升(hoisting)的深入理解(2)

因为这样的原因,推荐的做法是在申明变量的时候,将所用的变量都写在作用域(全局作用域或函数作用域)的最顶上,这样代码看起来就会更清晰,更容易看出来那个变量是来自函数作用域的,哪个又是来自作用域链(本文不对此多做解释,请读者自行百度,有机会再补充说明)。

重复声明

JS中作用域和变量提升(hoisting)的深入理解

上面的输出其实是:1 2 2。虽然看起来里面x申明了两次,但上面说了,js的var变量只有全局作用域和函数作用域两种,且申明会被提升,因此实际上x只会在最顶上开始的地方申明一次,var x=2的申明会被忽略,仅用于赋值。也就是说上面的代码实际上跟下面是一致的。

JS中作用域和变量提升(hoisting)的深入理解

函数和变量同时提升的问题

如果是函数和变量类型同时申明定义了,会发生什么事情呢?看下面的代码

JS中作用域和变量提升(hoisting)的深入理解


A

上面的输出结果其实是: function foo(){} ,也就是函数内容。

而如果是这样的形式呢

JS中作用域和变量提升(hoisting)的深入理解


B

它的输出却变成:undefined

为什么会这样呢?

原来函数提升分为两种情况:

一种:函数申明。就是上面A,function foo(){}这种形式

另一种:函数表达式。就是上面B,var foo=function(){}这种形式

第二种形式其实就是var变量的声明定义,因此上面的B输出结果为undefined应该就能理解了。

而第一种函数申明的形式,在提升的时候,会被整个提升上去,包括函数定义的部分!因此A跟下面的这种方式是等价的!

JS中作用域和变量提升(hoisting)的深入理解

原因是因为:1、函数声明被提升到最顶上;2、申明只进行一次,因此后面var foo='i am text'的申明会被忽略。

并且函数申明的优先级优于变量申明,所以以下形式的输出,同样是函数内容:

JS中作用域和变量提升(hoisting)的深入理解

总结

要彻底理解JS的作用域和Hoisting,只要记住以下三点即可:

1、所有申明都会被提升到作用域的最顶上

2、同一个变量申明只进行一次,并且因此其他申明都会被忽略

3、函数声明的优先级优于变量申明,且函数声明会连带定义一起被提升

注意:

通过with语句,可以临时改变运行期上下文的作用域链,此时的对非var定义的变量进行访问,会首先访问with中对象的属性,然后才会向上顺着作用域链向上检查该属性。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wzgdwx.html