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代码来阐述闭包,目的是为了使普通 ...
随机推荐
- wepack+sass+vue 入门教程(三)
十一.安装sass文件转换为css需要的相关依赖包 npm install --save-dev sass-loader style-loader css-loader loader的作用是辅助web ...
- load和initialize方法
一.load 方法什么时候调用: 在main方法还没执行的时候 就会 加载所有类,调用所有类的load方法. load方法是线程安全的,它使用了锁,我们应该避免线程阻塞在load方法. 在项目中使 ...
- 更愉快的书写CSS
我在写CSS的时候经常会碰到些麻烦事儿: 1)看上去蛮简单的排版却写了很久 2)代码写的越来越散,总是这里补一句,那里补一句,没有条理性 3)margin.padding.font-size等属性在不 ...
- JS继承之原型继承
许多OO语言都支持两种继承方式:接口继承和实现继承.接口继承只继承方法签名,而实现继承则继承实际的方法.如前所述,由于函数没有签名,在ECMAScript中无法实现接口继承.ECMAScript只支 ...
- [原] KVM虚拟机网络闪断分析
背景 公司云平台的机器时常会发生网络闪断,通常在10s-100s之间. 异常情况 VM出现问题时,表现出来的情况是外部监控系统无法访问,猜测可能是由于系统假死,OVS链路问题等等.但是在出现网络问题的 ...
- 【微信小程序开发】之如何获取免费ssl证书【图文步骤】
微信小程序要求所有网络请求都走ssl加密,因此我们开发服务端接口需要配置为https 这篇文章介绍一下如何 在 startssl 申请一个免费的ca证书. 1. 打开网站 https://www.s ...
- 自定义控件之 圆形 / 圆角 ImageView
一.问题在哪里? 问题来源于app开发中一个很常见的场景——用户头像要展示成圆的: 二.怎么搞? 机智的我,第一想法就是,切一张中间圆形透明.四周与底色相同.尺寸与头像相同的蒙板图片,盖在 ...
- linux系统oracle-ora12505问题解决方案一
说明:(1)Linux版本 Linux version 2.6.32.12-0.7-default (geeko@buildhost) (gcc version 4.3.4 [gcc-4_3-bran ...
- 【一起学OpenFOAM】03 OpenFOAM基本使用流程
OpenFOAM初学者常常对于软件的使用流程感到很迷惑,与其他的具有GUI的CFD软件不同,OpenFOAM的所有操作均为基于文本操作,譬如说里面各种计算模型.计算参数.流程控制参数等,均为通过修改对 ...
- 如何开启MySQL 5.7.12 的二进制日志
1. 打开/etc下的my.cnf文件 2. 编辑它,添加内容: log_bin=binary-log #二进制日志的文件名 server_id=1 #必须指定server_id,这是MySQL ...