块级作用域
由于作用域相关的东西太多,所以拆分成多个章节
一、作用域概述
二、标识符与作用域
三、全局和模块作用域
四、函数作用域
五、块作用域
六、作用域 与 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

浙公网安备 33010602011771号