JS闭包那些事
关于闭包,我曾经一直觉得它很讨厌,因为它一直让我很难搞,不过有句话怎么说来着,叫做你越想要一个东西,就要装作看不起它的样子。所以,抱着这个态度,我终于掳获了闭包。
首先来认识一下什么是闭包,闭包,一共有三大特征:
1 函数嵌套函数
2 内部的函数可以引用外部函数的参数和变量
3 参数和变量不会被垃圾回收机制所收回
举个栗子:
function aaa(){
var b = 5;
function bbb(){ b++; alert(b); } } aaa();
这个栗子就是很明显的闭包,函数里面嵌套函数,同时内部的函数bbb又可以访问到外部函数aaa中的变量,至于第三个特征,我们都知道在JS解析机制中,函数内的变量在函数调用完后会被销毁,但在这里b并没有被销毁,因为他还会被里面的函数bbb引用,那么怎么证明呢?
首先,我们要注意,在上面这个栗子中,是不会弹出值的,因为里面的函数bbb,只是声明了,并没有被调用,我们都知道,函数它不会主动执行的,那么怎么执行呢,看下面:
function aaa(){ var b = 5;
function bbb(){
b++; alert(b); // }
return bbb; } var c = aaa(); // 此时aaa被执行 同时把返回结果bbb 赋给c
c(); //
将里面的函数作为返回结果,然后可以调用,这种经常会遇见,当aaa执行后,返回结果为一个函数,然后再调用。e而且会弹出6,因为它的值被里面的函数改变。
现在知道了闭包的特征,那最重要的是知道它的好处和应用:
1 希望一个变量长期驻扎在内存当中
2 避免全局变量的污染
3 私用成员的存在
1 首先呢,我们肯定有过这样的需求,我们需要这样一个变量,在全局的很多地方都可以被改变,于是我们会声明一个全局变量,但是也就因为它可以在任何地方被改变,所以很容易出问题被污染。我们既希望它可以不被污染,又希望它可以在很多地方都能访问到,这样就闭包就产生了作用。
看个栗子。
function aaa(){
var a = 1;
return function(){
a++;
alert(a);
}
}
var c = aaa();
c(); //
c(); //
c(); //
当我们每调用一次,a的值就被累加,同时它又没有被污染,因为闭包的第三个特性,它的变量不会被垃圾机制回收,所以每调用一次都会在原来的基础上加1。
其实这个时候改写成更简单的方式,就是改成函数表达式:
var aaa =(function(){
var a = 1;
return function(){
a++;
alert(a);
}
})(); aaa(); //
aaa(); //
这样是不是省事很多了呢,如果不明白函数表达式,可以参考我前面的文章,讲的很清楚。
2 我们通过一个例子来看看第三个好处
var aaa =(function(){
var a = 1;
function bbb(){
a++;
alert(a);
}
function ccc(){
a++;
alert(a);
}
return {
b:bbb,
c:ccc
} // 返回json对象 })(); aaa.b(); //
aaa.c(); //
当在一个函数里声明了多个函数,可以通过json的格式返回,然后我们就可以在外面这样调用,这些函数就成了函数aaa的私有成员,如果对json不太了解,可以我看看w3cschool的介绍,很好理解。
3 下面我们看第三个栗子。它非常优秀的体现了闭包的优点,就是我们经常写的选项卡切换的例子,一般我们会循环给每个列表加上一个索引,通过闭包就不用再加索引了。
在循环中直接找到对应元素的索引。如下 没循环一次 内部函数调用一次 将i的值直接作为参数传进去。
window.onload = function(){
var aLi = document.getElementsByTagName('li');
for(var i=0;i<aLi.length;i++){
(function(i){
aLi[i].onclick = function(){
alert(i);
}
})(i);
} }
上面代码就是在点击事件的函数的外面再加上一个函数,就形成了闭包,然后每循环一次,通过函数表达式的形式,将i传进去,而通过闭包特性可以知道,事件绑定的函数就可以访问外面函数里面的参数i。
其实还有另一种写法:
window.onload = function(){
var aLi = document.getElementsByTagName('li'); for(var i=0;i<aLi.length;i++){
aLi[i].onclick = (function(i){
return function(){
alert(i);
}
})(i);
} }
这种方法的原理是这样的,首先将一个函数表达式的调用赋给了点击事件,我们都知道,当事件后面等于的不是函数名,而直接是调用的话,那不点击,函数也已经执行了,所以在循环的时候,i已经作为参数,传进了函数表达式,而这个函数表达式的返回值又是一个函数,函数嵌套,闭包关系,这个函数可以访问外面函数传进来的每个i。
如果是初学者,不熟悉选项卡,可以先去了解选项卡原理。
闭包需要注意的地方(这个先做简单了解 后续会补充详细)
1 在IE下有可能引发内存泄漏 (内存泄漏指当你的页面跳转的时候 内存不会释放 一直占用你的CPU 只有当你关闭了浏览器才会被释放)
内存泄漏产生的条件:
当获取一个节点或者一组节点 然后又给这个节点添加了属性( 比如事件) 而在事件内部你又引用外部的东西。
解决;
1 在页面未加载的时候将添加的属性去掉
window.onunload = function(){
odiv.onclick = null;
} 2 var id = odiv.id;
odiv.onclick = function(){ alert(id);
}
odiv = null;
JS闭包那些事的更多相关文章
- js闭包的作用域以及闭包案列的介绍:
转载▼ 标签: it js闭包的作用域以及闭包案列的介绍: 首先我们根据前面的介绍来分析js闭包有什么作用,他会给我们编程带来什么好处? 闭包是为了更方便我们在处理js函数的时候会遇到以下的几 ...
- js闭包和ie内存泄露原理
也议 js闭包和ie内存泄露原理 可以, 但小心使用. 闭包也许是 JS 中最有用的特性了. 有一份比较好的介绍闭包原理的文档. 有一点需要牢记, 闭包保留了一个指向它封闭作用域的指针, 所以, 在给 ...
- 简单详细讲解js闭包(看完不懂你砍我!!!)
<javascript高级程序设计>中闭包的概念: 闭包,其实是一种语言特性,它是指的是程序设计语言中,允许将函数看作对象,然后能像在对象中的操作般在函数中定义实例(局部)变量,而这些变量 ...
- 大部分人都会做错的经典JS闭包面试题
由工作中演变而来的面试题 这是一个我工作当中的遇到的一个问题,似乎很有趣,就当做了一道题去面试,发现几乎没人能全部答对并说出原因,遂拿出来聊一聊吧. 先看题目代码: function fun(n,o) ...
- Js闭包常见三种用法
Js闭包特性源于内部函数可以将外部函数的活动对象保存在自己的作用域链上,所以使内部函数的可以将外部函数的活动对象占为己有,可以在外部函数销毁时依然存有外部函数内的活动对象内容,这样做的好处是可 ...
- js闭包之初步理解( JavaScript closure)
闭包一直是js中一个比较难于理解的东西,而平时用途又非常多,因此不得不对闭包进行必要的理解,现在来说说我对js闭包的理解. 要理解闭包,肯定是要先了解js的一个重要特性, 回想一下,那就是函数作用域, ...
- (原创)JS闭包看代码理解
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="C ...
- js闭包理解
js闭包的作用是使函数外可以访问函数内部的变量,是通过 在函数内部 定义 访问函数内变量 的函数实现的,内部的一个函数产生一个闭包 function a() { var i=0; return fun ...
- js闭包理解实例小结
Js闭包 闭包前要了解的知识 1. 函数作用域 (1).Js语言特殊之处在于函数内部可以直接读取全局变量 <script type="text/javascript"> ...
随机推荐
- Effective Java 65 Don't ignore exceptions
Principle An empty catch block defeats the purpose of exceptions, which is to force you to handle ex ...
- 基于python的flask的应用实例注意事项
1.所有的html文件均保存在templates文件夹中 2.运行网页时python manage.py runserver
- spring ioc DI 理解
下面是我从网上找来的一些大牛对spring ioc和DI的理解,希望也能让你对Spring ioc和DI的设计思想有更进一步的认识. 一.分享Iteye的开涛对Ioc的精彩讲解 Ioc—Inversi ...
- db2 常用命令(一)
DB2数据库常用命令小结 ========操作数据库命令========== -- 启动数据库实例 #db2start -- 停止数据库实例 #db2sto # 如 ...
- SecureCRT 使用技巧
VanDyke CRT 和 VanDyke SecureCRT是最常用的终端仿真程序,简单的说就是windows下登录UNIX或Liunx服务器主机的软件.二者不同的是SecureCRT支持SSH∗( ...
- Hive query issue
One time, I have written a query with two tables join, One table is big table with partitions , anot ...
- cni 添加网络 流程分析
cnitool: Add or remove network interfaces from a network namespace cnitool add <net> <netns ...
- jquery中attr和prop的区别(转)
在网络上看到这样一篇关于jquery中attr和prop的区别文章,觉得不错,所以转载了. 在jQuery 1.6中,.attr()方法查询那些没有设置的属性,则会返回一个undefined.如果你要 ...
- 第23章 SEH结构化异常处理(2)_编译器对系统SEH机制的封装
23.2 编译器层面对系统SEH机制的封装 23.2.1 扩展的EXCEPTION_REGISTRATION级相关结构:VC_EXCEPTION_REGISTRATION (1)VC_EXCEPTIO ...
- IO流的练习1 —— 随机获取文本中的信息
需求:一个文本中有几个名字,随机从中获取一个名字 分析: A:首先把文本中的数据读出 B:再把数据存储到集合中 C:产生一个随机的索引 D:打印出这个索引对应的值 public static void ...