js的函数作用域跟块级作用域(声明提升问题)

一,js中的作用域

    js中除了全局作用域,还有函数作用域。

    嗯,还有块级作用域。

二,函数作用域跟块级作用域的区别

    当将代码看成一个IIFE时,全局作用域其实就是一个函数作用域。

    那么函数作用域跟块级作用域的区别是什么呢?

          函数作用域:变量在定义的函数内及嵌套的子函数内处处可见;

          块级函数域:变量在离开定义的块级代码后马上被回收。

    那么为什么两者会有这样的区别呢?

    因为在函数作用域内,变量声明有一个提升hoisting的过程。

 

              图2-1

    let定义的变量具有块级作用域,待会讲。

扫描二维码关注公众号,回复: 1270233 查看本文章

    如果var定义的变量跟let定义的变量一样没有hoisting的过程,那么两者应该都是ReferenceError,但是结果发现bundefined,说明b发生了提升,其效果如下:

 

              图2-2

三,hoisting

    js中只有两种情况下会发生提升:声明了一个变量(如果是定义了一个变量,则分离成声明跟赋值,提取声明操作,函数也是一等变量),或者定义了一个函数声明

 

              图3-1

    可见,单纯的声明会提升,

    定义变量,则提取其声明操作提升,

    函数声明会完全提升。

    那如果在提升的时候发生重命名了怎么办?

 

    如图3-2,照之前所说的提升,实际运行前的代码应该为图3-3

 

    那么之后的var a为什么没有覆盖掉function a(){}这个定义,使第一个打印为undefined

    因为编译器在遇到变量声明时(函数表达式可以理解为包含了声明和赋值的操作),会先查看当前作用域,如果该变量不存在,则在该作用域中声明该变量;如果存在,则会忽略该声明。所以引擎实际接收的代码应该是图3-4

 

            图3-4

    注意不要把a跟隐式全局变量混淆

四,块级作用域

    嗯,js中还是存在块级作用域的。

4.1 catch捕获的异常

    

    图4-1catch块捕获的异常只在catch块中可见

    但是catch块中定义的其他变量还是属于整个函数作用域的。

4.2 let关键字

     如图4-2let定义的变量遵从块级作用域,不会提升,不会在整个函数域内起作用

     

             图4-2

4.3 const关键字

     const定义的变量是在let的基础上,如图4-3,增加了必须在声明时赋值为一个常量的限制,如图4-4

     

             图4-3

 

     

             图4-4

 

五,其他

5.1 出现的error

    ReferenceError:作用域判别错误,通过作用域链的搜寻找不到相应的变量。

    TypeError:可以通过作用域搜索到变量,但是对变量的操作不合法。

    SyntaxError:语法错误

 

5.2 hoisting中的函数声明

    直接在函数体内定义的函数声明,整个都会提前;

    但是在块中定义的函数声明,只会提升其声明部分,不分配实际的内存空间。如图5-1

 

        图5-1

猜你喜欢

转载自blog.csdn.net/hansexploration/article/details/80014236
今日推荐