闭包是什么?

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

内部函数不仅可以访问外部函数的变量,也能访问外部函数的参数(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 闭包深入浅出的更多相关文章

  1. 《Web 前端面试指南》1、JavaScript 闭包深入浅出

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

  2. JavaScript闭包(Closure)

    JavaScript闭包(Closure) 本文收集了多本书里对JavaScript闭包(Closure)的解释,或许会对理解闭包有一定帮助. <你不知道的JavsScript> Java ...

  3. Javascript闭包和C#匿名函数对比分析

    C#中引入匿名函数,多少都是受到Javascript的闭包语法和面向函数编程语言的影响.人们发现,在表达式中直接编写函数代码是一种普遍存在的需求,这种语法将比那种必须在某个特定地方定义函数的方式灵活和 ...

  4. javascript闭包理解

    //闭包理解一 function superFun(){ var _super_a='a'; function subfuc(){ console.log(_super_a); } return su ...

  5. Javascript闭包深入解析及实现方法

    1.什么是闭包 闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.闭包的特点:1. 作为一个函数变量的一个引用,当函数返回时 ...

  6. javascript闭包和作用域链

    最近在学习前端知识,看到javascript闭包这里总是云里雾里.于是翻阅了好多资料记录下来本人对闭包的理解. 首先,什么是闭包?看了各位大牛的定义和描述各式各样,我个人认为最容易一种说法: 外部函数 ...

  7. JavaScript闭包深入解析

    for (var i=1; i<=5; i++) { setTimeout( function timer() { console.log( i ); }, i*1000 ); } --上面这段 ...

  8. JavaScript 闭包系列二(匿名函数及函数的闭包)

    一. 匿名函数 1. 函数的定义,可分为三种 1) 函数声明方式 function double(x) {     return 2*x; } 2)Function构造函数,把参数列表和函数体都作为字 ...

  9. JavaScript闭包模型

      JavaScript闭包模型 -----  [原创翻译]2016-09-01  09:32:22 < 一>  闭包并不神秘 本文利用JavaScript代码来阐述闭包,目的是为了使普通 ...

随机推荐

  1. 前端框架 EasyUI (1)熟悉一下EasyUI

    jQuery EasyUI 官方网站 http://www.jeasyui.com/ .去年新开了个中文网 http://www.jeasyui.net/,不知道是不是官方的,不过看着挺像样.但是,广 ...

  2. ASP.NET Aries 入门开发教程7:DataGrid的行操作(主键操作区)

    前言: 抓紧勤奋,再接再励,预计共10篇来结束这个系列. 上一篇介绍:ASP.NET Aries 入门开发教程6:列表数据表格的格式化处理及行内编辑 本篇介绍主键操作区相关内容. 1:什么时候有默认的 ...

  3. .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理

    .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理 0x00 问题的产生 管道是.NET Core中非常关键的一个概念,很多重要的组件都以中间件的形式存在,包括权限管理.会话管理 ...

  4. SSH实战 · 唯唯乐购项目(中)

    用户模块 三:一级分类的查询 创建一级分类表并导入基本数据 CREATE TABLE `category` (   `cid` int(11) NOT NULL AUTO_INCREMENT,   ` ...

  5. JS里面Data日期格式转换

    var format = function(time, format){     var t = new Date(time);     var tf = function(i){return (i  ...

  6. SQL Server常见数据类型介绍

    数据表是由多个列组成,创建表时必须明确每个列的数据类型,以下列举SQL Server常见数据类型的使用规则,方便查阅. 1.整数类型 int 存储范围是-2,147,483,648到2,147,483 ...

  7. MVC通过路由实现URL重写

    public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Ro ...

  8. the Zen of Python---转载版

    摘自译文学习区 http://article.yeeyan.org/view/legendsland/154430 The Zen of Python Python 之禅 Beautiful is b ...

  9. BPM合同管理解决方案分享

    一.方案概述合同是组织与组织间所订协议的法律 表现形式,体现着双方对于合作在法律和道德上的承诺.然而,大多数企业的合同管理都或多或少存在合同审批过程不规范.签订草率.审批权责不清.合同执行跟踪难.合同 ...

  10. iOS之绘制虚线

    /*   ** lineFrame:     虚线的 frame   ** length:        虚线中短线的宽度   ** spacing:       虚线中短线之间的间距   ** co ...