zoukankan      html  css  js  c++  java
  • JavaScript 闭包深入浅出

    闭包是什么?

    闭包是内部函数可以访问外部函数的变量。它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量。

    内部函数不仅可以访问外部函数的变量,也能访问外部函数的参数(parameters)。但注意,它只能访问外部函数的 parameters ,而不能访问外部函数的 arguments 对象。

    举例说明

    JavaScript 闭包

    function showName (firstName, lastName) {

    ​   var nameIntro = "Your name is ";
        // 内部函数可以访问外部函数的变量(nameInfo)、parameter (firstName、lastName)
        ​function makeFullName () {
        
            ​return nameIntro + firstName + " " + lastName;
    
        }
    ​
        ​return makeFullName ();

    }

    ​
    showName ("Michael", "Jackson"); // Your name is Michael Jackson

    Jquery 闭包

    $(function() {
        ​var selections = [];
        // 能访问 selections 变量
        $(".niners").click(function() {
            // 能更新变量 selections
            selections.push (this.prop("name"));
        });
    });

    闭包的规则和副作用

    即使是被返回的闭包仍然可以访问外部函数的变量

    JavaScript 的执行时候的作用域和创建时候的作用域是一样的。这也就是说即使被外部函数返回后,内部函数仍然能访问外部函数的变量。

    function celebrityName (firstName) {
        var nameIntro = "This celebrity is ";
       function lastName (theLastName) {
            return nameIntro + firstName + " " + theLastName;
        }
        return lastName;
    }
    ​
    ​var mjName = celebrityName ("Michael");// 这个时候外部方法 celebrityName 已经被返回了
    ​
    ​// 闭包仍然可以访问外部方法的变量和参数
    mjName ("Jackson"); // This celebrity is Michael Jackson


    闭包存储的是外部函数的变量的引用

    存储的不是实际的值,在闭包被调用之前,如果外部函数中变量的值发生改变,会变得更有意思。

    function celebrityID () {
        var celebrityID = 999;
        // 返回的包含内部函数的对象
        return {
            getID: function ()  {
                // 内部函数返回的是更新以后的 celebrityID 变量值
                return celebrityID;
            },
            setID: function (theNewID)  {
                // 内部函数随时都能改变外部函数内的变量。
                celebrityID = theNewID;
            }
        }
    }
    ​
    ​var mjID = celebrityID (); // 此时,外部函数的 celebrityID 变量被改变。
    mjID.getID(); // 999​
    mjID.setID(567); // 改变外部函数的 celebrityID 变量。
    mjID.getID(); // 567

    闭包的副作用

    开发中有如下情况

    function celebrityIDCreator (theCelebrities) {
        var i;
        var uniqueID = 100;
        for (i = 0; i < theCelebrities.length; i++) {
          theCelebrities[i]["id"] = function ()  {
            return uniqueID + i;
          }
        }
    
        return theCelebrities;
    }
    ​
    ​var actionCelebs = [{name:"Stallone", id:0},
        {name:"Cruise", id:0},
        {name:"Willis", id:0}
    ];
    ​
    ​var createIdForActionCelebs = celebrityIDCreator (actionCelebs);
    ​
    ​var stalloneID = createIdForActionCelebs [0];
    
    console.log(stalloneID.id()); // 103

    在调用匿名函数的时候,uniqueID 已经加了 数字 3 变成 103,生成的 celebritiesID 也是 103,数组的每个元素也就是都是 103,而不是 100、101、102。

    这是因为闭包(也即是例子中的内部匿名函数)访问的是外部函数的变量的引用,而不是变量的值。为了解决这个 BUG,我们可以使用一种 ** Immediately Invoked Function Expression ** (IIFE)(立即执行函数语法),代码如下:

    function celebrityIDCreator (theCelebrities) {
        var i;
        var uniqueID = 100;
        for (i = 0; i < theCelebrities.length; i++) {
            theCelebrities[i]["id"] = function (j)  {
                // 这里的 j 参数也就是在 调用(IIFE)时传过来的参数 i。
                return function () {
                    return uniqueID + j;
                    // 依次接收传递过来 i 值,然后把它保存在数组中。
                } () // 通过在 function 末尾处加 () ,可以立即执行它,然后只返回 uniqueID + j 的值,而不是 一个 function。
            } (i); // 传递过来一个 i 变量作为匿名函数的参数,并立即执行它。
        }
    ​
        return theCelebrities;
    }
    ​
    ​var actionCelebs = [{name:"Stallone", id:0}, {name:"Cruise", id:0}, {name:"Willis", id:0}];
    ​
    ​var createIdForActionCelebs = celebrityIDCreator (actionCelebs);
    ​
    ​var stalloneID = createIdForActionCelebs [0];
    
    console.log(stalloneID.id); // 100​​
    
    ​var cruiseID = createIdForActionCelebs [1];

    
    console.log(cruiseID.id); // 101

    

     
     
    关注我
  • 相关阅读:
    基本类型与引用类型
    局部变量与实例变量
    语句块
    i++与++i
    JAVA基本概念
    网线8根线的排列方式
    Docker容器常用命令
    内存cache使用的场景
    Python爬虫:Xpath语法笔记
    python实现简单的聊天
  • 原文地址:https://www.cnblogs.com/libin-1/p/6257702.html
Copyright © 2011-2022 走看看