• Javascript之旅——第十站:为什么都说闭包难理解呢?


     

    研究过js的朋友大多会说,理解了js的原型和闭包就可以了,然后又说这些都是js的高级内容,然后就又扯到了各种神马的作用域。。。然后不少人就会被忽悠的云里雾里。。。下面我也试着来说说闭包,看我说的这个是否浅显易懂。。。

    一:闭包含义

    闭包是个专业词汇,这样才能显得在js中是高大上的货色,官方定义我这里就不敢修改它,定义如下:就是有权访问另一个函数作用域的变量的函数。

    二:一个简单的场景

    上面的定义大概也能看得懂,但是不知道为什么不把“另一个函数” 改成 “包含函数”,因为我觉得“包含函数”可能更通俗易懂些,光有定义还不行,我还得找个经典的例子看一看。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <script type="text/javascript">
     
            //比较函数
            function createComparison(propertyName) {
     
                return function (obj1, obj2) {
                    var item1 = obj1[propertyName];
                    var item2 = obj2[propertyName];
     
                    if (item1 < item2)
                        return -1;
     
                    if (item1 > item2)
                        return 1;
     
                    if (item1 == item2)
                        return 0;
                }
            }
     
            //比较name
            var compare = createComparison("name");
     
            var result = compare({ name: "d", age: 20 }, { name: "c", age: 27 });
        </script>

    这是一个说闭包原理的经典例子,经典在哪里?如例子中我使用compare时,我的function是可以访问到createComparison函数中的propertyName字段的,其实这个理解并不复杂,我们去看看浏览器的scope variables就一清二楚了。

    我们可以清楚的看到,在chrome的本地变量表中清楚的记录着当前执行函数中的本地变量列表,并且还进行了分类,比如上面的”局部函数变量(Local)“,”包含函数变量(Closure)”,“全局变量(Global)”,那下面有个有趣的问题就来了,chrome怎么知道我代码执行到20行的时候,当前的local variables有哪些呢?而且还能给我分门别类,是不是太奇葩了????但是仔细推敲一下就能豁然开朗,肯定有一个变量保存着当前的variables,不然的话,chrome去哪读取呢?对不对????????

    三:解开谜底

    其实在每个function里面都有一个scope属性,当然这个属性被引擎屏蔽了,你是看不见也摸不着的,它里面就保存着当前函数的 local variables,如果应用到上面demo的话,就是全局函数中有一个scope,createComparison有一个scope,匿名的compare有一个scope,而且这三个scope还是通过链表链接的,画个简图如下:

    从上面简图中可以看到,其实整个函数中有三个scope,每个scope都是用next指针链接,这样就形成了一个链表,当我执行下面代码的时候

    1
    var result = compare({ name: "d", age: 20 }, { name: "c", age: 27 });

    js引擎会拿到当前compare的scope,通过scope属性的next指针,就可以区分哪些变量属于哪个函数,这样你就看到了chrome对variables的分门别类了。

    四:对一个案例的加深理解

    我想读到这里,你应该明白了闭包的原理,其实没什么稀奇的,就是一个读取scope属性的问题。只是被装逼成高大上了,下面看段代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <script type="text/javascript">
     
            var arr = new Array();
     
            function Person() {
                for (var i = 0; i < 10; i++) {
     
                    //要记住,这个属性函数申明,只有立即执行才会取scope属性
                    var item = function () {
                        return i;
                    };
     
                    arr.push(item);
                }
            }
     
            Person();
     
            for (var i = 0; i < arr.length; i++) {
                console.log(arr[i]());
            }
        </script>

    在这个例子中,我想做一个function()数组的array,并且最后都能输出各自的值(1,2,3,4,5…10),但是结果又是怎样呢?可以看到下图中输出的其实是10个10。。。这样就违背了我的原始意图。

    上面这个陷阱的最大问题在于你自以为我在匿名function中写了return i;就认为它是属于匿名函数的,其实这就大错特错了,因为这个i就算走到天涯海角都不属于匿名函数,而是属于它的包含函数Person,所以原理应该是这样,比如你看,当我执行arr[0]()的时候,这时候匿名函数就会通过scope去找i,但是在匿名函数的scope中没有i,所以就通过next找到了Person函数,确实在Person中找到了i,但是这个时候i已经是10了,然后结束scope查找输出10。解决方案也很简单,给每个匿名function一个副本就好了,具体原理我想你应该可以用scope推测出来了,对不对。


    原文出处: 一线码农的博客   欢迎分享原创到伯乐头条

  • 相关阅读:
    [Automation] 自动化测试工具和测试框架大集合
    C#借助API实现黑盒自动化测试工具的编写
    C#实现RSA加密解密
    Uipath开发过程中最常见的5类错误
    tqdm介绍及常用方法
    Top-1准确率和Top-5准确率
    focal loss焦点损失
    【深度学习】卷积神经网络中Dropout、BatchNorm的位置选择
    数据增强——mixup
    数据增强之mixup算法详解
  • 原文地址:https://www.cnblogs.com/sunscheung/p/4342133.html
Copyright © 2020-2023  润新知