接触过javascript的人应该听过闭包(closure),有一种观点认为是闭包赋予了javascript的强大能力,也赋予了它具备OOP的特征。既然javascript closure如此重要,那么问题来了,什么是closure呢?closure有什么作用?本文将结合我自己对closure的理解,用尽量通俗易懂的方式来进行阐述。

  先看看老外对closure怎么定义的?A closure is an inner function that has access to the outer (enclosing) function's variables—scope chain.从字面上来看,可以翻译为:闭包就是一个内部函数,它具备访问外部函数变量(这些变量位于作用域链中)的能力[注意变量不包含this和arguments]。但这个概念还是过于“专业化”, 不接地气,只从概念上来看,非常抽象。下面用一段JS来对应解释闭包的概念:

个人理解为:fInner函数定义在fOuter的内部,可以访问fOuter定义的变量,这个fInner函数就是closureclosure的 scope chain有3个一个是fInner函数定义的变量;一个是外部fOuter的变量;还有一个是全局变量(global variables)。closure的作用可以保留变量的值换句话说,函数fInner就是一个closure

  closure可以干2件事情:

  1)closure可以调用(闭包存储的外部变量是引用而不是值,这点非常重要)在当前函数以外的定义的变量(即使外部函数已经返回);

  2)closure可以修改外部定义的变量值

下面通过一段JS代码来阐述为什么闭包存储的外部变量是引用而不是值,这点非常重要

     function mixFunction(a)
{
var result=[],i,n;
n=a.length;
for(i=0;i<n;i++){
result[i]=function(){
//Closure对外部变量是引用
console.log("for i="+i);
return a[i];//a[i-1]
}
}
return result;
}
var mixcall=mixFunction([10,20,30]);
var f=mixcall[0];
console.log(f());//?应该输出什么值

f()会输出 10 么?答案是undefined!!!

为什么是这样的呢? 因为闭包对i是引用,在for循环时,会不断更新i的值。即在调用f()后,i已经被修改为3 (i===3),而a[3]为undefined!!

上述的代码始终会输出a[2]的值,也就是30。

那么问题来了?怎么解决该问题呢?这就要用到JS中的IIFE技术啦!IIFE技术来解决JS缺少块级作用域的解决方案。如下代码所示:

     function mixFunctionFix(a)
{
var result=[],i,n;
n=a.length;
for(i=0;i<n;i++){
//IIFE技术来解决JS缺少块级作用域的解决方案
(function(j){
result[i]=function(){
//Closure对外部变量是引用
console.log("for j="+j);
return a[j];
}
})(i)
}
return result;
}
var mixcall=mixFunctionFix([10,20,30]);
var f=mixcall[0];
console.log(f());//

前面提到JS闭包可以实现OOP的特征,下面给出JS如何定义一个“User类”(实际是一个JS函数)。此函数有私用变量和方法,同时也具有公开的方法。私有变量和方法不能函数外部调用:

     function User(){
//private properties
var _name = '';
var _age = 0; //private method
function privateMethod(){
return "private Method"
};
//public method
this.setName = function(name){
//can call
privateMethod();
_name = name;
return this;
}; this.setAge = function(age){
_age = age;
return this;
};
this.getAge = function(){
return _age;
};
this.getName = function(){
return _name;
};
}
var p=new User();
console.log(p.setName('jackwang').setAge(28));
console.log(p.getName());//jackwang
console.log(p.getAge());//
console.log(p._name);//undefined
console.log(p.privateMethod());//error

私有变量_name和_age以及私有方法privateMethod()都不能在函数外部调用。User设置name和age只能通过公开方法setName和setAge进行,获取只能通过getName和getAge进行访问。

有人会问,这个是闭包么?看下图:

如何理解javascript closure ?的更多相关文章

  1. 【转】深入理解JavaScript闭包闭包(closure) (closure)

    一.什么是闭包?"官方"的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.相信很少有人能直接看懂这句话,因为他描述 ...

  2. 理解Javascript 的闭包(closure)

    要理解闭包的概念先从变量的作用域说去 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之 ...

  3. 深入理解JavaScript的闭包特性如何给循环中的对象添加事件

    初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...

  4. 深入理解JavaScript闭包【译】

    在<高级程序设计>中,对于闭包一直没有很好的解释,在stackoverflow上翻出了一篇很老的<JavaScript closure for dummies>(2016)~ ...

  5. (转)深入理解JavaScript 模块模式

    深入理解JavaScript 模块模式 (原文)http://www.cnblogs.com/starweb/archive/2013/02/17/2914023.html 英文:http://www ...

  6. 深入理解javascript的闭包

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域 ...

  7. 深入理解javascript闭包(一)

    闭包(closure)是Javascript语言的一个难点.也是它的特色,非常多高级应用都要依靠闭包实现. 一.什么是闭包? 官方"的解释是:闭包是一个拥有很多变量和绑定了这些变量的环境的表 ...

  8. 深入理解javascript闭包(一)

    原文转自脚本之家(http://www.jb51.net/article/24101.htm) 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. ...

  9. 深入理解Javascript闭包概念

    一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部能够直接读取全局变量 ...

随机推荐

  1. python socket 学习

    Python在网络通讯方面功能强大,今天学习一下Socket通讯的基本方式,分别是UDP通讯和TCP通讯. UDP通讯 upd 服务端 #!/usr/bin/env python # -*- codi ...

  2. wangEditor——轻量级web富文本框

    提示:最新版wangEditor请参见  http://www.wangeditor.com/  和   https://github.com/wangfupeng1988/wangEditor 交流 ...

  3. CSS字体

    字体系列 [1]5种通用字体系列:拥有相似外观的字体系列 serif字体:字体成比例,且有上下短线,包括Times\Georgia\New century Schoolbook sans-serif字 ...

  4. 后端码农谈前端(CSS篇)第七课:定位与浮动

    一.定位: 1.定位的理解 (1)相对定位 相对定位是一个非常容易掌握的概念.如果对一个元素进行相对定位,它将出现在它所在的位置上.然后,可以通过设置垂直或水平位置,让这个元素"相对于&qu ...

  5. Abp公共连接和事务管理方法

    Conection 和事务管理在使用数据库的应用中是一个最重要的概念.当你打开一个连接,开始一个事务,如何来处理这些连接等等. 您也许知道,.NET使用了连接池.所以,创建一个连接实际上是从连接池里得 ...

  6. hadoop中MapReduce多种join实现实例分析

    转载自:http://zengzhaozheng.blog.51cto.com/8219051/1392961 1.在Reudce端进行连接. 在Reudce端进行连接是MapReduce框架进行表之 ...

  7. SQL Server利用RowNumber()内置函数与Over关键字实现通用分页存储过程(支持单表或多表结查集分页)

    SQL Server利用RowNumber()内置函数与Over关键字实现通用分页存储过程,支持单表或多表结查集分页,存储过程如下: /******************/ --Author:梦在旅 ...

  8. ios基础之 view的frame 与 bounds 的区别 (转)

    前言: 学习ios开发有一段时间了,项目也做了两个了,今天看视频,突然发现view的frame和bound两个属性,发现bound怎么也想不明白,好像饶你了死胡同里,经过一番尝试和思考,终于弄明白bo ...

  9. AudioCapabilities成员

    参考:http://www.ajerp.com/Cs/DirectX/Capture/DirectX.Capture.html 使用有道翻译2.0 AudioCapabilities成员 公共实例字段 ...

  10. C#多种方式获取文件路径

    string str5=Application.StartupPath;//获取启动了应用程序的可执行文件的路径,不包括可执行文件的名称. string str1 =Process.GetCurren ...