JavaScript 闭包深入浅出
闭包是什么?
闭包是内部函数可以访问外部函数的变量。它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量。
内部函数不仅可以访问外部函数的变量,也能访问外部函数的参数(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

JavaScript 闭包深入浅出的更多相关文章
- 《Web 前端面试指南》1、JavaScript 闭包深入浅出
闭包是什么? 闭包是内部函数可以访问外部函数的变量.它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量. 内部函数不仅可以访问外 ...
- JavaScript闭包(Closure)
JavaScript闭包(Closure) 本文收集了多本书里对JavaScript闭包(Closure)的解释,或许会对理解闭包有一定帮助. <你不知道的JavsScript> Java ...
- Javascript闭包和C#匿名函数对比分析
C#中引入匿名函数,多少都是受到Javascript的闭包语法和面向函数编程语言的影响.人们发现,在表达式中直接编写函数代码是一种普遍存在的需求,这种语法将比那种必须在某个特定地方定义函数的方式灵活和 ...
- javascript闭包理解
//闭包理解一 function superFun(){ var _super_a='a'; function subfuc(){ console.log(_super_a); } return su ...
- Javascript闭包深入解析及实现方法
1.什么是闭包 闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.闭包的特点:1. 作为一个函数变量的一个引用,当函数返回时 ...
- javascript闭包和作用域链
最近在学习前端知识,看到javascript闭包这里总是云里雾里.于是翻阅了好多资料记录下来本人对闭包的理解. 首先,什么是闭包?看了各位大牛的定义和描述各式各样,我个人认为最容易一种说法: 外部函数 ...
- JavaScript闭包深入解析
for (var i=1; i<=5; i++) { setTimeout( function timer() { console.log( i ); }, i*1000 ); } --上面这段 ...
- JavaScript 闭包系列二(匿名函数及函数的闭包)
一. 匿名函数 1. 函数的定义,可分为三种 1) 函数声明方式 function double(x) { return 2*x; } 2)Function构造函数,把参数列表和函数体都作为字 ...
- JavaScript闭包模型
JavaScript闭包模型 ----- [原创翻译]2016-09-01 09:32:22 < 一> 闭包并不神秘 本文利用JavaScript代码来阐述闭包,目的是为了使普通 ...
随机推荐
- 【WCF】错误协定声明
在上一篇烂文中,老周给大伙伴们介绍了 IErrorHandler 接口的使用,今天,老周补充一个错误处理的知识点——错误协定. 错误协定与IErrorHandler接口不同,大伙伴们应该记得,上回我们 ...
- Android 6.0 权限知识学习笔记
最近在项目上因为6.0运行时权限吃了亏,发现之前对运行时权限的理解不足,决定回炉重造,重新学习一下Android Permission. 进入正题: Android权限 在Android系统中,权限分 ...
- HTML骨架结构
前面的话 一个完整的HTML文档必须包含3个部分:文档声明.文档头部和文档主体.而正是它们构成了HTML的骨架结构.前面已经分别介绍过文档声明和文档头部,本文将详细介绍构成HTML骨架结构的基础元 ...
- .Net Core上用于代替System.Drawing的类库
目前.Net Core上没有System.Drawing这个类库,想要在.Net Core上处理图片得另辟蹊径. 微软给出了将来取代System.Drawing的方案,偏向于使用一个单独的服务端进行各 ...
- JAVA 设计模式之策略模式
定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换. 类型:行为类模式 策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换.在前面说过 ...
- linux下 lvm 磁盘扩容
打算给系统装一个oracle,发现磁盘空间不足.在安装系统的时候我选择的是自动分区,系统就会自动以LVM的方式分区.为了保证系统后期的可用性,建议所有新系统安装都采用LVM,之后生产上的设备我也打算这 ...
- Linux实战教学笔记07:Linux系统目录结构介绍
第七节 Linux系统目录结构介绍 标签(空格分隔):Linux实战教学笔记 第1章 前言 windows目录结构 C:\windows D:\Program Files E:\你懂的\精品 F:\你 ...
- windows系统路径环境变量
当前系统盘符%systemdrive%或%HOMEDRIVE%C:\ 当前系统目录%systemroot%或%Windir%C:\WINDOWS 当前用户文件夹%UserProfile%或%HOMEP ...
- 技术笔记:Indy的TIdSMTP改造,解决发送Html和主题截断问题
使用Indy来发邮件坑不少啊,只不过有比没有好吧,使用delphi6这种老工具没办法,只能使用了新一点的Indy版本9,公司限制... 1.邮件包含TIdText和TIdAttachment时会出现T ...
- Ubuntu Server(Ubuntu 14.04 LTS 64位)安装libgdiplus2.10.9出错问题记录
首先下载libgdiplus2.10.9安装包 wget http://download.mono-project.com/sources/libgdiplus/libgdiplus-2.10.9.t ...