javascript的闭包

闭包闭包闭包,屁包屁包屁包

一、什么是闭包

javascript里面,所有的函数都是闭包!

这句断言真是惊天地,泣鬼神。不过,通常意义上的闭包是指:某个函数内部的子函数,这个子函数被外界所调用,用于访问父函数(就是那个该死的“某个函数”啦)内的变量(包括参数)。

从中可以看出,我们常常说的闭包是:

1)首先,闭包是一个函数

2)其次,闭包是一个子函数,就是说,它是一个嵌套在函数里的子函数,函数中的函数

3)这个子函数有什么用呢?它会被外界访问,外界通过访问它来访问和操控它所在的父函数中的变量

不过也有一种说法,说闭包是一种特殊的对象,这个对象包括函数和创建该函数的环境。这个环境是指什么呢?我觉得是指父函数中的那些变量。

一个典型的闭包如下:

function a() {
 var i = 0;
 function b() { alert(++i); }
 return b;
}
var c = a();
c();

其中,b就是那个传说中的闭包。

当 函数a 的 内部函数b 被 函数a外的一个变量 引用的时候,就创建了一个 闭包。

二、闭包有什么用

1、外界访问函数内部变量的桥梁

如上所述

好处就是封装,提高私密性

2、保护父函数的内部变量,避免被JS的垃圾回收机制回收

看回开头那个例子:

[javascript] view plaincopy

  1. function a() {
  2. var i = 0;
  3. function b() { alert(++i); }
  4. return b;
  5. }
  6. var c = a();
  7. c();

var i 是函数a的内部变量,在语句 var c = a(); 运行之后,函数a已经运行结束,按照一般的理解,i 就应该被回收了(或者说被打上回收标志了),不可再用了。但这段代码正常运行,一点问题没有,原因就在于闭包:b 被 c 引用,而 b 依赖于 i,因此,i 免遭垃圾回收。

3、闭包被调用的时候,会如同面向对象中创建实例一样,将父函数的内部变量(包括父函数传入的参数)克隆一份。被调用多少次,就创建多少份,每份都各自独立,互不影响。

看看这个例子:

页面中有如下HTML代码:

[html] view plaincopy

  1. <p id="help">Helpful notes will appear here</p>
  2. <p>E-mail: <input type="text" id="email" name="email"></p>
  3. <p>Name: <input type="text" id="name" name="name"></p>
  4. <p>Age: <input type="text" id="age" name="age"></p>

然后我们试图通过JS代码实现这样的效果:光标停在不同的文本框,就显示不同的提示信息

[javascript] view plaincopy

  1. function showHelp(help) {
  2. document.getElementById(‘help‘).innerHTML = help;
  3. }
  4. function setupHelp() {
  5. var helpText = [
  6. {‘id‘: ‘email‘, ‘help‘: ‘Your e-mail address‘},
  7. {‘id‘: ‘name‘, ‘help‘: ‘Your full name‘},
  8. {‘id‘: ‘age‘, ‘help‘: ‘Your age (you must be over 16)‘}
  9. ];
  10. for (var i = 0; i < helpText.length; i++) {
  11. var item = helpText[i];
  12. document.getElementById(item.id).onfocus = function() {
  13. showHelp(item.help);
  14. }
  15. }
  16. }
  17. setupHelp();

结果没有达到预期的结果,文本框获得焦点的时候,全部提示最后一个提示信息:‘Your age (you must be over 16)‘

为什么会这样呢?

赋给onfocus事件的,是一个个匿名函数。这些匿名函数,使用了父函数setupHelp里的变量 item。因此,从这个意义上来说,这些匿名函数是闭包(别看item是在循环体内定义的,但在父函数setupHelp里,处处都能访问, javascript就是这么怪。可能在javascript里,变量的作用域都是对函数而言的)。当onfocus事件被激发的时候,循环早已结束,此时item因为匿名函数是闭包的缘故,它还存活着,但值是指向helpText最后一项的。而因为那几个匿名函数引用的都是item,因此出现所有提示都相同的情况。

怎么办呢?应该在循环中,将每一次的item都保留下来。

完成这项任务的,还是闭包。因为闭包对变量的保护,无微不至。闭包就是为了操控内部变量而存在。如果世界上有一种爱是真爱,那就是闭包对变量的爱。闭包闭包闭包,屁包屁包屁包。

[javascript] view plaincopy

  1. //看,这里有一个闭包,提供了对变量help(参数也算内部变量)的保护
  2. function showHelp(help) {
  3. return function(){document.getElementById(‘help‘).innerHTML = help;};
  4. }
  5. function setupHelp() {
  6. var helpText = [
  7. {‘id‘: ‘email‘, ‘help‘: ‘Your e-mail address‘},
  8. {‘id‘: ‘name‘, ‘help‘: ‘Your full name‘},
  9. {‘id‘: ‘age‘, ‘help‘: ‘Your age (you must be over 16)‘}
  10. ];
  11. for (var i = 0; i < helpText.length; i++) {
  12. var item = helpText[i];
  13. document.getElementById(item.id).onfocus = showHelp(item.help);//这里也稍有改动
  14. }
  15. }
  16. setupHelp();

如此,目的可达到矣。每一次循环的item,都通过闭包机制,好好地保存下来了。

三、闭包虽好,可别滥用

1、由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2、闭包会在父函数外部,改变父函数内部变量的值。所以一定要小心,不要随便改变父函数内部变量的值。

参考文章:

http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Closures

http://www.jb51.net/article/24101.htm

有一个网站很好,可以在里面写JS、HTML等进行测试

http://jsfiddle.net/

时间: 2024-10-18 13:19:49

javascript的闭包的相关文章

javascript 关于闭包的知识点

javascript 关于闭包的认识 概念:闭包(closure)是函数对象与变量作用域链在某种形式上的关联,是一种对变量的获取机制. 所以要大致搞清三个东西:函数对象(function object).作用域链(scope chain)以及它们如何关联(combination) 首先要建立一个印象,在js中,几乎所有的东西可以看作对象,除了null和undefined.比如常用的数组对象.日期对象.正则对象等. var num = 123; // Number var arr = [1,2,3

javascript Closure 闭包

引用自 http://www.cnblogs.com/mguo/archive/2013/06/19/3143880.html /*一.变量的作用域要理解闭包,首先必须理解Javascript特殊的变量作用域.变量的作用域无非就是两种:全局变量和局部变量.Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量.*/ var n=999; function f1(){ alert(n); } f1(); // 999//另一方面,在函数外部自然无法读取函数内的局部变量. funct

JavaScript中闭包实现的私有属性的getter()和setter()方法

注意: 以下的输出都在浏览器的控制台中 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>闭包</title> </head> <body> <script type="text/javascript"> /** * 利用闭包实现 * 这个函数给对象o增加了属性存储器方法 * 方法名称为ge

javascript学习-闭包

javascript学习-闭包 1.什么是闭包 大多数书本中对闭包的定义是:“闭包是指有权访问另一个函数作用域中的变量的函数.”.这个概念过于抽象了,对初学者而言没啥帮助.好在<Javascript忍者秘籍>5.1中给了一个例子来进一步的解释了什么是闭包: var outerValue= 'ninja'; var later; function outerFunction() { var innerValue = "samurai"; function innerFunct

两个示例介绍JavaScript的闭包

JavaScript的闭包有两个用途:一个是访问函数内部的变量:另一个是让变量的值在作用域内保持不变.函数是JavaScript 中唯一有作用域的对象,因此JavaScript的闭包依赖于函数实现,下面结合两则示例对JavaScript的闭包做简单说明. 1. 访问函数内部的变量 JavaScript中没有严格意义上的类,所以我们常用函数来模拟类.我们可以像下面这样模拟一个Counter类,并在其中定义一个count私有变量: 在JavaScript中,函数可以访问其外部定义的变量,而外部不能访

JavaScript基础–闭包

JavaScript基础–闭包 理解闭包的概念对于学习JavaScript至关重要,很多新手(包括我)开始学习闭包时,都会感觉似懂非懂,之前看了一些资料,整理了闭包的一篇博客,若有疏忽与错误,希望大家多多给意见. 概述 理解闭包的概念前,建议大家先回想一下JS作用域的相关知识,如果有疑问的同学,可以参考:JavaScript基础–作用域.闭包的定义如下: Closure is when a function is able to remember and access its lexical s

javascript中闭包的工作原理

一.什么是闭包? 官方”的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.相信很少有人能直接看懂这句话,因为他描述的太学术.其实这句话通俗的来说就是:JavaScript中所有的function都是一个闭包.不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的“闭包”.看下面这段代码: 1 2 3 4 5 6 7 function a() { var i = 0; function b() { ale

关于Javascript的闭包

要理解javascript的闭包 关键是弄明白三样事情 1.变量作用域 一言以蔽之  函数内部可以访问函数外部的字段  而反之不行 1 var n=999; 2 3 function f1(){ 4 alert(n); 5 } 6 7 f1(); // 999 1 function f1(){ 2 var n=999; 3 } 4 5 alert(n); // error 此处有一坑是 若在函数内声明变量不使用var关键字 相当于是声明全局变量 也就是window的变量 2.this的含义 th

javascript中闭包的原理与用法小结(转)

一.在javaScript中闭包的五种表现形式如下: 1 /** 2 * Created by admin on 2016/12/26. 3 *//* 4 //向函数对象添加属性 5 function Circle(r){ 6 this.r=r; 7 } 8 Circle.prototype.PI=3.1415926; 9 Circle.prototype.area=function(){ 10 return this.PI*this.r*this.r; 11 }; 12 var c=new C

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

初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript的闭包特性. 有个网友问了个问题,如下的html,为什么点击所有的段落p输出都是5,而不是alert出对应的0,1,2,3,4. <!DOCTYPE HTML> <html> <head> <meta charset="utf-8" /> &