轻松理解javascript闭包

前言:闭包允许JavaScript程序员编写更好的代码。创意、表达和简洁。我们经常在JavaScript中使用闭包,不管您的JavaScript经验如何,您无疑会一次又一次地遇到它们。当然,闭包可能看起来很复杂,超出了您的范围,但是在阅读本文之后,闭包将更容易理解,因此对您的日常JavaScript编程任务更有吸引力。

闭包是什么?
闭包是一个内部函数,它可以访问外部(封闭)函数的变量范围链。闭包有三个范围链:它可以访问它自己的范围(在它的花括号中定义的变量),它可以访问外部函数的变量,并且它可以访问全局变量。
内部函数不仅可以访问外部函数的变量,还可以访问外部函数的参数。注意,内部函数不能调用外部函数的参数对象,尽管它可以调用外部函数的参数

A Basic Example of Closures in JavaScript:

function showName (firstName, lastName) {

​var nameIntro = "Your name is ";
// this inner function has access to the outer function's variables, including the parameter​
​function makeFullName () {

​return nameIntro + firstName + " " + lastName;

}

​return makeFullName ();

}


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


在node . js中大量使用闭包;它们是节点中的工作马。js的异步非阻塞的架构。在jQuery中,闭包也经常被使用,几乎所有的JavaScript代码都被使用。

A Classic jQuery Example of Closures:

$(function() {
   ​var selections = [];
   $(".niners").click(function() { // this closure has access to the selections variable​
      selections.push (this.prop("name")); // update the selections variable in the outer function's scope​
   });
});

闭包的规则和副作用

即使在外部函数返回后,闭包也可以访问外部函数的变量:
1.闭包最重要和最棘手的特性之一是,即使在外部函数返回后,内部函数仍然能够访问外部函数的变量。是的,你没看错。当JavaScript的函数执行时,它们使用的范围链在创建时生效。这意味着即使在外部函数返回后,内部函数仍然可以访问外部函数的变量。因此,可以稍后调用内部函数

unction celebrityName (firstName) {
var nameIntro = "This celebrity is ";
// this inner function has access to the outer function's variables, including the parameter​
function lastName (theLastName) {
return nameIntro + firstName + " " + theLastName;
}
return lastName;
}

​var mjName = celebrityName ("Michael"); // At this juncture, the celebrityName outer function has returned.​

​// The closure (lastName) is called here after the outer function has returned above​
​// Yet, the closure still has access to the outer function's variables and parameter​
mjName ("Jackson"); // This celebrity is Michael Jackson


2.Closures store references to the outer function’s variables;

闭包存储对外部函数的变量的引用;它们不存储实际值。
闭包获得更多有趣的外部函数的变量的值改变时调用之前关闭。这个强大的功能可以用创造性的方式来利用,比如这个私有变量的例子首先由Douglas Crockford演示:
function celebrityID () {
var celebrityID = 999;
// We are returning an object with some inner functions​
// All the inner functions have access to the outer function's variables​
return {
getID: function () {
// This inner function will return the UPDATED celebrityID variable​
// It will return the current value of celebrityID, even after the changeTheID function changes it​
return celebrityID;
},
setID: function (theNewID) {
// This inner function will change the outer function's variable anytime​
celebrityID = theNewID;
}
}

}

​var mjID = celebrityID (); // At this juncture, the celebrityID outer function has returned.​
mjID.getID(); // 999​
mjID.setID(567); // Changes the outer function's variable​
mjID.getID(); // 567: It returns the updated celebrityId variable


3.Closures Gone Awry

由于闭包能够访问外部函数的变量的更新值,因此当外部函数的变量与for循环发生变化时,它们也会导致bug。因此:

// This example is explained in detail below (just after this code box).​
​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

在前面的例子中,当调用匿名函数时,i的值是3(数组的长度,然后是增量)。数字3被添加到“独特”中,为所有的名人创建了103。因此,返回数组中的每个位置都得到id = 103,而不是预期的100、101、102。
The reason this happened was because, as we have discussed in the previous example, the closure (the anonymous function in this example) has access to the outer function’s variables by reference, not by value. So just as the previous example showed that we can access the updated variable with the closure, this example similarly accessed the i variable when it was changed, since the outer function runs the entire for loop and returns the last value of i, which is 103.

要修复闭包中的这个副作用(bug),您可以使用一个立即调用的函数function celebrityIDCreator (theCelebrities) {
function celebrityIDCreator (theCelebrities) {
var i;
var uniqueID = 100;
for (i = 0; i < theCelebrities.length; i++) {
theCelebrities[i]["id"] = function (j) { // the j parametric variable is the i passed in on invocation of this IIFE​
return function () {
return uniqueID + j; // each iteration of the for loop passes the current value of i into this IIFE and it saves the correct value to the array​
} () // BY adding () at the end of this function, we are executing it immediately and returning just the value of uniqueID + j, instead of returning a function.​
} (i); // immediately invoke the function passing the i variable as a parameter​
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值