《Web 前端面试指南》一、JavaScript 闭包深刻浅出

闭包是什么?

闭包是内部函数能够访问外部函数的变量。它能够访问三个做用域:首先能够访问本身的做用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量。javascript

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

举例说明

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 的执行时候的做用域和建立时候的做用域是同样的。这也就是说即便被外部函数返回后,内部函数仍然能访问外部函数的变量。jquery

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、10一、102。函数

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

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
相关文章
相关标签/搜索