zoukankan      html  css  js  c++  java
  • 闭包&作用域链&let

    1. 概念

    闭包函数:声明在一个函数中的函数,叫做闭包函数。
    闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)之后。
    

    2. 特点

    • 可以实现在外部访问函数内部变量。
    • 可以避免全局污染。
    • 局部变量常驻内存,会造成内存泄漏。

    3. 作用域链

    在js中,常见作用域分为全局作用域、函数作用域、块级作用域,作用域有上下级关系,上下级关系的确定就看函数是在哪个作用域下创建的,如果要搞清楚闭包问题,就需要了解作用域链。

    如图,当c函数中没有x,y变量时就会按照作用域链往上级找直到找到同名变量,作用域链:c函数作用域->b函数作用域->a函数作用域->全局作用域

    作用域链

    4.案例

       for (var i = 0; i < 5; i++) {
           setTimeout(function () {
               console.log(i++);
           }, 2000)
       }
       console.log(i);
       /* 输出 5 5 6 7 8 9 */
    

    执行步骤

    1.全局执行上下文进入执行栈
    2.每次执行1个for循环将会发生:将1个setTimeout任务放到浏览器定时触发线程,到达时间后将回调放入任务队列(事件循环),i++
    4.执行for循环外的输出任务(输出5)
    5.全局执行上下文出栈,同步代码执行完毕
    6.任务队列的任务依次进栈->执行(console.log(i++))->出栈(每次栈里只有一个任务)(5 6 7 8 9)
    7.执行完毕

    由于定时器回调函数未定义i,输出的i根据作用域链找到全局的i(由于存在闭包,全局执行完 i不会被回收),回调执行时i已经是变成5了。

    解决方法1:使用自执行函数

    for (var i = 0; i < 5; i++) {
        (function (x) {
            // var x = i;相当于有这么一句
            setTimeout(function () {
                console.log(x++);
            }, 2000)
        })(i);
    }
    console.log(i);/* 结果 5 0 1 2 3 4 */
    

    执行步骤与修改前大致相同,区别在于每次循环都会将自执行函数进栈出栈,也就是说每个自执行函数对应的x在不同内存空间的,定时器访问的x是各个自执行函数中的独有x,而不是全局的i,所以输出的值不会受i后续变化的影响。
    解决办法2:使用let声明

    for (let i = 0; i < 5; i++) {
        setTimeout(function () {
            console.log(i++);
        }, 2000)
    }
    /* 输出 0 1 2 3 4 */
    

    首先说明let和var的区别,let相对于var具有不支持变量提升、不可重复定义、块级作用域等特点,由于let块级作用域的特点,for循环中每一层循环对应一块作用域,每个回调函数寻找的上级的i也是属于不同作用域的。

  • 相关阅读:
    UVA 11174 Stand in a Line,UVA 1436 Counting heaps —— (组合数的好题)
    UVA 1393 Highways,UVA 12075 Counting Triangles —— (组合数,dp)
    【Same Tree】cpp
    【Recover Binary Search Tree】cpp
    【Binary Tree Zigzag Level Order Traversal】cpp
    【Binary Tree Level Order Traversal II 】cpp
    【Binary Tree Level Order Traversal】cpp
    【Binary Tree Post order Traversal】cpp
    【Binary Tree Inorder Traversal】cpp
    【Binary Tree Preorder Traversal】cpp
  • 原文地址:https://www.cnblogs.com/aeipyuan/p/12726199.html
Copyright © 2011-2022 走看看