一、作用域
    作用域规定了变量保存与读取规则:一般情况下,内部作用域可以访问外层作用域中的变量,外部作用域无法读取内部作用域的数据。
    js中作用域大概分为: 全局作用域,函数作用域,es6新增的会计作用域(for循环体和花括号’{}’,还有使用函数参数默认值时产生)
    二、闭包
    1、通俗理解:可以引用其他函数内部变量的函数。
    开发者可以把数据保存在函数内部作用域独立管理,通过闭包的形式向外界提供访问权限。
    2、闭包常见形式
    可以访问其他函数内部变量的函数
    (1)返回的内部函数
    (2)函数作为参数调用
    三、闭包应用
    1、数据缓存

    1. function myCache(){
    2. let cache = {};
    3. return {
    4. set(key, val){
    5. cache[key] = val
    6. },
    7. get(key){
    8. return cache[key]
    9. }
    10. }
    11. }
    12. let cacheTool = myCache()

    2、防抖节流函数

    四、解决循环输出问题

    1. for(var i=1;i<=5;i++){
    2. setTimeout(function() {
    3. console.log(i)
    4. }, 0)
    5. }

    1、为什么会打印6
    js解析器的运行规则:声明变量时,先查询该变量是否已经在当前作用域声明,如果已经声明则会对变量进行赋值操作。
    (1)setTimeout和主线程同步代码都是宏任务,循环体执行完以后,全局作用域中保存了值为6的变量i
    (2)之后执行setTimeout的回调函数,回调函数引用着全局作用域中的变量i,所以打印的都是6
    2、解决方法
    (1)给setTimeout传入第三个参数,在执行回调时作为参数传递给回调函数
    (2)循环体中用let声明变量,可以创建多个作用域,分别保存不同的i变量供setTimeout回调引用
    (3)利用匿名立即执行函数(IIFE),创建多个作用域,和let的原理一样