《Web 前端面试指南》1、JavaScript 闭包深入浅出
闭包是什么?
闭包是内部函数可以访问外部函数的变量。它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量。
内部函数不仅可以访问外部函数的变量,也能访问外部函数的参数(parameters)。但注意,它只能访问外部函数的 parameters ,而不能访问外部函数的 arguments 对象。
举例说明
JavaScript 闭包
<code>function showName (firstName, lastName) { <br/> var nameIntro = "Your name is ";<br/> // 内部函数可以访问外部函数的变量(nameInfo)、parameter (firstName、lastName)<br/> function makeFullName () { <br/> return nameIntro + firstName + " " + lastName; <br/> }<br/> <br/> return makeFullName (); <br/> } <br/> <br/> showName ("Michael", "Jackson"); // Your name is Michael Jackson<br/> </code>
Jquery 闭包
<code>$(function() {<br/> var selections = [];<br/> // 能访问 selections 变量<br/> $(".niners").click(function() {<br/> // 能更新变量 selections<br/> selections.push (this.prop("name"));<br/> });<br/> });<br/> </code>
闭包的规则和副作用
即使是被返回的闭包仍然可以访问外部函数的变量
JavaScript 的执行时候的作用域和创建时候的作用域是一样的。这也就是说即使被外部函数返回后,内部函数仍然能访问外部函数的变量。
<code>function celebrityName (firstName) {<br/> var nameIntro = "This celebrity is ";<br/> function lastName (theLastName) {<br/> return nameIntro + firstName + " " + theLastName;<br/> }<br/> return lastName;<br/> }<br/> <br/> var mjName = celebrityName ("Michael");// 这个时候外部方法 celebrityName 已经被返回了<br/> <br/> // 闭包仍然可以访问外部方法的变量和参数<br/> mjName ("Jackson"); // This celebrity is Michael Jackson <br/> </code>
闭包存储的是外部函数的变量的引用
存储的不是实际的值,在闭包被调用之前,如果外部函数中变量的值发生改变,会变得更有意思。
<code>function celebrityID () {<br/> var celebrityID = 999;<br/> // 返回的包含内部函数的对象<br/> return {<br/> getID: function () {<br/> // 内部函数返回的是更新以后的 celebrityID 变量值<br/> return celebrityID;<br/> },<br/> setID: function (theNewID) {<br/> // 内部函数随时都能改变外部函数内的变量。<br/> celebrityID = theNewID;<br/> }<br/> }<br/> }<br/> <br/> var mjID = celebrityID (); // 此时,外部函数的 celebrityID 变量被改变。<br/> mjID.getID(); // 999<br/> mjID.setID(567); // 改变外部函数的 celebrityID 变量。<br/> mjID.getID(); // 567<br/> </code>
闭包的副作用
开发中有如下情况
<code>function celebrityIDCreator (theCelebrities) {<br/> var i;<br/> var uniqueID = 100;<br/> for (i = 0; i < theCelebrities.length; i++) {<br/> theCelebrities[i]["id"] = function () {<br/> return uniqueID + i;<br/> }<br/> } return theCelebrities;<br/> }<br/> <br/> var actionCelebs = [{name:"Stallone", id:0},<br/> {name:"Cruise", id:0},<br/> {name:"Willis", id:0}<br/> ];<br/> <br/> var createIdForActionCelebs = celebrityIDCreator (actionCelebs);<br/> <br/> var stalloneID = createIdForActionCelebs [0]; console.log(stalloneID.id()); // 103<br/> </code>
在调用匿名函数的时候,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];
转发申明:
本文转自互联网,由小站整理并发布,在于分享相关技术和知识。版权归原作者所有,如有侵权,请联系本站,将在24小时内删除。谢谢