闭包是什么?

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

内部函数不仅可以访问外部函数的变量,也能访问外部函数的参数(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

《Web 前端面试指南》1、JavaScript 闭包深入浅出的更多相关文章

  1. web前端面试试题总结---javascript篇

    JavaScript 介绍js的基本数据类型. Undefined.Null.Boolean.Number.String. ECMAScript 2015 新增:Symbol(创建后独一无二且不可变的 ...

  2. 《Web 前端面试指南》2、JavaScript 的 Bind 函数进阶

    使用 Bind() 设置方法中 this 对象 //<button>获取随机的人</button>​ //<input type="text"> ...

  3. web前端面试系列 一 js闭包

    一.什么是闭包? JavaScript高级程序设计第三版: 闭包是指有权访问另一个函数作用域中的变量的函数. 在js中定义在函数内部的子函数能够访问外部函数定义的变量,因此js内部函数就是一个闭包. ...

  4. web前端面试总结

    本文由我收集总结了一些前端面试题,初学者阅后也要用心钻研其中的原理,重要知识需要系统学习.透彻学习,形成自己的知识链.万不可投机取巧,临时抱佛脚只求面试侥幸混过关是错误的!也是不可能的! 前端还是一个 ...

  5. web前端面试试题总结---html篇

    HTML Doctype作用?标准模式与兼容模式各有什么区别? (1).<!DOCTYPE>声明位于位于HTML文档中的第一行,处于 <html> 标签之前.告知浏览器的解析器 ...

  6. web前端面试试题总结---其他

    其他问题 原来公司工作流程是怎么样的,如何与其他人协作的?如何夸部门合作的? 你遇到过比较难的技术问题是?你是如何解决的? 设计模式 知道什么是singleton, factory, strategy ...

  7. web前端面试试题总结---css篇

    CSS 介绍一下标准的CSS的盒子模型?低版本IE的盒子模型有什么不同的? (1)有两种, IE 盒子模型.W3C 盒子模型: (2)盒模型: 内容(content).填充(padding).边界(m ...

  8. Web前端面试笔试题总结

    最近一段时间要毕业了,忙着找工作,见过不少笔试面试题,自己总结了一些加上网上找的一些整合了一下.答案暂时都东拼西凑出来了,但是还是先不发出来,一方面是答案并不是唯一的并且自己的答案不能保证对,另一方面 ...

  9. 2016年Web前端面试题目汇总

    转载: 2016年Web前端面试题目汇总 以下是收集一些面试中经常会遇到的经典面试题以及自己面试过程中未解决的问题,通过对知识的整理以及经验的总结,重新巩固自身的前端基础知识,如有错误或更好的答案,欢 ...

随机推荐

  1. Online Judge(OJ)搭建(第一版)

    搭建 OJ 需要的知识(重要性排序): Java SE(Basic Knowledge, String, FileWriter, JavaCompiler, URLClassLoader, Secur ...

  2. NodeJs在Linux下使用的各种问题

    环境:ubuntu16.04 ubuntu中安装NodeJs 通过apt-get命令安装后发现只能使用nodejs,而没有node命令 如果想避免这种情况请看下面连接的这种安装方式: 拓展见:Linu ...

  3. CMS模板应用调研问卷

    截止目前,已经有数十家网站与我们合作,进行了MIP化改造,在搜索结果页也能看到"闪电标"的出现.除了改造方面的问题,MIP项目组被问到最多的就是:我用了wordpress,我用了织 ...

  4. Java数据库连接技术——JDBC

    大家好,今天我们学习了Java如何连接数据库.之前学过.net语言的数据库操作,感觉就是一通百通,大同小异. JDBC是Java数据库连接技术的简称,提供连接各种常用数据库的能力. JDBC API ...

  5. svn 常用命令总结

    svn 命令篇 svn pget svn:ignore // 查看忽略项 svn commit -m "提交说明" // 提交修改 svn up(update) // 获取最新版本 ...

  6. Android学习探索之Java 8 在Android 开发中的应用

    前言: Java 8推出已经将近2年多了,引入很多革命性变化,加入了函数式编程的特征,使基于行为的编程成为可能,同时减化了各种设计模式的实现方式,是Java有史以来最重要的更新.但是Android上, ...

  7. [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?

    你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...

  8. javaScript生成二维码(支持中文,生成logo)

    资料搜索 选择star最多的两个 第一个就是用的比较多的jquery.qrcode.js(但不支持中文,不能带logo)啦,第二个支持ie6+,支持中文,根据第二个源代码,使得,jquery.qrco ...

  9. SAP CRM 性能小技巧

    导言 本页面打算收集SAP CRM实施中可以用于避免性能问题的注意事项,重要的事项会由图标标识. 如果你有其他的技巧想要说出来,别犹豫! 性能注意事项 通用 缓存读取类访问,特别是在性能关键的地方,比 ...

  10. SQL字符串函数

    LEN() :计算字符串长度(字符的个数.)datalength();//计算字符串所占用的字节数,不属于字符串函数.测试varchar变量与nvarchar变量存储字符串a的区别.见备注1.LOWE ...