闭包是什么?

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

内部函数不仅可以访问外部函数的变量,也能访问外部函数的参数(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前端面试试题总结---其他

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

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

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

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

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

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

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

  9. 百度web前端面试2015.10.18

    邮件里通知的周日下午两点参加百度校招面试,我13:10分就到了,前台先让我拿了个面试资格单(上面是我的信息),然后在web前端面试入口排队,面试在百度食堂举行的,等了大概1个小时,放我去面试.都是一对 ...

随机推荐

  1. CodeChef - QCHEF 分块

    题目链接:http://vjudge.net/problem/174774/origin 题意:给定一个长度为n的序列a[],序列的值不大于m,现在有k个询问,每个询问给定(l,r).让你求出max{ ...

  2. CentOS 6.5 安装HDFS集群(Hadoop-2.7.3)

    安装真实集群,而不是但节点或者伪分布式,以3个节点为例,node1为NameNode和SecondNameNode,node2和node3为DataNode. 1.3台机器的配置必须要一模一样,只需要 ...

  3. 【干货】解密监控宝Docker监控实现原理

    分享人高驰涛(Neeke),云智慧高级架构师,PHP 开发组成员,同时也是 PECL/SeasLog 的作者.8 年研发管理经验,早期从事大规模企业信息化研发架构,09 年涉足互联网数字营销领域并深入 ...

  4. PHP中的多态

    多态的概念一般是强类型语言来谈的,因为强类型语言它必须要声明参数类型,比如一个手电筒对象的打开方法其参数申明了只能是蓝光,就不能传其他光.但可以用父类渲染的方式使其多态,比如声明一个光的父类,让其它颜 ...

  5. kail新手安装

    Kali Linux下载链接:http://mirrors.ustc.edu.cn/kali-images/kali-2.0/ (ps:建议用国内镜像源下载,速度有保证) Kali Linux安装之后 ...

  6. mysql 强制走索引

    查询是数据库技术中最常用的操作.查询操作的过程比较简单,首先从客户端发出查询的SQL语句,数据库服务端在接收到由客户端发来的SQL语句后, 执行这条SQL语句,然后将查询到的结果返回给客户端.虽然过程 ...

  7. PHP5的对象复制

    今天用yii开发程序,一个bug改了一晚上,最后发现问题出在了对象复制机制上,PHP5之前的对象复制只需要$object_a = $object_b即可,但PHP5这样得到的是浅复制,及指针指向,并不 ...

  8. Oracle绑定变量优缺点

    参考:http://f.dataguru.cn/thread-208881-1-1.html 参考:http://blog.sina.com.cn/s/blog_4d9ece9a0100caw8.ht ...

  9. pip更新

    python -m ** install -U **

  10. 谁在用 Hadoop

    谁在用 Hadoop这是个问题.在大数据背景下,Apache Hadoop已经逐渐成为一种标签性,业界对于这一开源分布式技术的了解也在不断加深.但谁才是 Hadoop的最大用户呢?首先想到的当然是它的 ...