块级作用域

由于作用域相关的东西太多,所以拆分成多个章节

一、作用域概述

二、标识符与作用域

三、全局和模块作用域

四、函数作用域

五、块作用域

六、作用域 与 this

跨级作用域本身没有声明可以说的,就需要注意两点:

1.跨级作用域内声明的var变量并不会存在这个块级作用域内,而是会提升到非块级作用域内

2.在块级作用域内声明function,在不同浏览器会有不同结果,如果是根据条件声明function的话,请用var func = function的形象

 

但是为什么会把块级作用域单独拎出来说呢,原因在于块级作用域和循环结合的时候,就会有一些奇怪的表现了

在之前,很常见的一道面试题是这样子的,请说出会打印出什么?

for(var i = 0; i < 5; i++){
  setTimeout(() => {console.log(i)})  
}

 当然,结果很显然,是5个5,接着面试官又会问,如果想打印出0,1,2,3,4 需要怎么做呢?

这里有几种的做法,比如使用闭包,最简单的就是把var 变成let,这样就可以了

for(let i = 0; i < 5; i++){
  setTimeout(() => {console.log(i)})  
}

 ok,为什么改成let 就可以了呢?这里i只声明了一次,为什么每次调用console.log会得到不同的值?

 

其作用原理在于:遍历词法声明,如果是let声明,则push到names,在每次循环的时候,遍历names创建对应的变量,并且用上一次循环结束时候每个letNames的结果作为初始化值,

  也就是说,每次遍历都会创建新的变量,所以我们能够得到不同的值,其过程大概像下面:

 注:我们返回一个值,其实返回的是一个包含这个值的对象,在es中称之为:CompletionRecord
        result:{ type: return|break|continue|throw|normal, value, },包含结果值和返回类型
  比如 return 3, 那么 result:{type: return, value:3}
      比如 throw new Error(),那么 result: {type: throw, value: new Error()}
 
{
    // for 循环的块级作用域
    let i = 0;
    //在这里如果声明了一个函数,那么函数访问的始终是i=0的值,
    //比如 for(let i = 0, showI = ()=>{console.log(i)}; i < 5; i++) { showI() },打印出来的是5个0,

    //第一次循环开始,创建新的块级作用域
    let i = 0
   //执行check:i < 5
   //如果check为false,则跳出循环
   //执行循环体代码,得到一个结果result
     // 检测result,看是否还能继续循环
     

    //第二次循环开始,创建新的块级作用域
    let i = 1
    i++
   //执行check:i < 5
   //如果check为false,则跳出循环
   //执行循环体代码,得到一个结果result
    // 检测result,看是否还能继续循环

    //第三次循环开始,创建新的块级作用域
    //...
}

  

当然,就算是var声明的话,也会每次循环都会创建一个块级作用域,但是如最开始提到的那样,var声明是不会存在块级作用域的,所以var声明的i,在多次循环内都是同一个i
 
 
posted @ 2021-02-06 20:02  唐强136  阅读(229)  评论(0)    收藏  举报