1.变量的作用域:全局变量、局部变量

  • 函数内部可以直接读取局部变量

js代码

var n=2;

function fun(){

alert(n);

}

fun();  //2

  • 函数外部不能读取函数内部局部变量

js代码

function fun(){

var n=2;    //注意这里要使用var,否则声明的是全局变量

}

alert(n); //error

  • 下面n声明为全局变量

js代码

function fun(){

n=2;}
alert(n); //2


2.如何从外部读取局部变量?

  有时候需要得到函数内部的局部局部变量,正常情况下是办不到的,只有变通才有可能。在函数内部在定义一个函数

js代码

function fun(){

var n=2;

function f2(){

alert(n); //2

}

}

上面代码,f2函数包含在fun函数中,这时fun内部的局部变量对f2是可见的,而f2内部局部变量,对fun不可见,这就是javascript"链式作用域"结构

子对象会一级一级向上寻找所有父对象的变量,即父对象的所有变量对子对象都可见,反之则不成立

js代码

function fun(){

var n=2;

function f2(){

alert(n);

}

return f2;

}

var result=fun();

result(); //2


3.闭包概念

上面f2函数就是闭包

闭包简单理解就是:能够读取其他函数内部变量的函数,即将函数内部与函数外部连接起来的桥梁


4.闭包的用途

事实上,通过使用闭包,可以做很多事情。比如:模拟面向对象的代码风格;更优雅,更简洁地表达出代码;在某些方面提升代码的执行效率

注:根据上面知识可知,所有的变量如果不加关键字,则默认会添加到全局对象的属性上,临时变量加入全局变量有很多坏处,如:别的函数可能误用这些变量,造成全局对象过于庞大,影响访问速度(因为变量的取值需要从原型链上遍历)。

4.1匿名子执行函数

有些函数只需执行一次,其内部变量无序维护,比如UI的初始化,我们可以使用闭包

js代码

var datamodel={
table:[];
tree:[];
}
(function(dm){
for(var i=0;i<dm.table.rows;i++){
var row=dm.table.rows[i];
for(var j=0;j<row.cells;i++){
drawCell(i,j);
}
}
//build dm.tree
})(datamodel);

创建一个匿名函数并立即执行它,由于外部无法引用它内部的变量,因此在执行完后会很快被释放,最主要的是这种机制不会污染全局变量

4.2 缓存

  如果我们正在处理过程很耗时的函数对象,每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找的值即可。

  闭包正是可以做到这一点,因为它不会释放外部的引用,函数内部的值可以得到保留。减少全局变量,常驻内存,可以实现缓存

js代码

function f1(){
var n=99;
nAdd=function(){
n+=1;
}
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result();//99
nAdd();
result();//100

为什么f1中的局部变量n一直保存在内存中,没有在f1调用结束后自动清除?

f1是f2的父函数,f2被赋给全局变量,导致f2始终在内存中,而f2的存在依赖f1,因此f1也始终在内存中,不会再调用结束后,被垃圾回收机制回收

4.3 实现封装

4.3.1如下例子,在person之外的地方无法访问其内部的变量,通过提供闭包的形式来访问

js代码

 var person=function(){
var name="jack";
return{
getName:function(){
return name;
},
setName:function(newName){
name=newName;
}
}
}();
alert(person.name); //直接访问结果为:undefined
alert(person.getName()); //jack
person.setName("lihua");
alert(person.getName()); //lihua

4.3.2

  闭包另一个重要用途是实现面向对象中的对象,传统的语言都提供类的模板机制,这样不同的对象(类的实例)拥有独立的成员及状态,互不干涉。虽然javascript中没有类这样的机制,但通过使用闭包,可以模拟出这样的机制。

js代码

function person(){
var name="jack";
return{
getName:function(){
return name;
},
setName:function(newName){
name=newName;
}
}
};
var jone=person();
alert(jone.getName()); //jack
jone.setName("lihua");
alert(jone.getName()); //lihua var miss=person();
alert(miss.getName());
miss.setName("wanghai");
alert(miss.getName());

以上代码中Jone和miss可以成为person这个类的实例,因为这两个实例对name这个成员的访问时独立的,互补影响。

5使用闭包应该注意问题

5.1内存泄露

  闭包会使函数中的变量都保存在内存中,内存消耗大,故不能滥用闭包,否则造成网页性能问题(浏览器响应速度慢、降低用户体验甚至会造成浏览器无响应等现象),在IE中可能导致内存泄露

5.2上下文应用

jQuery代码

$(function(){

var con=$("div#panel");

this.id="content";

con.click(function(){

alert(this.id); //panel

});

});

  this.id 显示的被赋值content,而在click回调中,形成的闭包引用到this.id,但这个alert会弹出"panel",原因:虽然闭包可以引用局部变量,但此处涉及到this,因为调用对象的存在,使得闭包被调用时(当这个panel的click事件发生时),此处的this引用的是con这个jQuery对象,而匿名函数this.id="content"是对匿名函数本身做的操作。

如果想在事件中处理函数中访问的这个值,则必须做些改变

$(function(){

var con=$("div#panel");

this.id="content";

var self=this;

con.click(function(){

alert(self.id); //content

});

});

初探js闭包的更多相关文章

  1. 从273二手车的M站点初探js模块化编程

    前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数 ...

  2. js闭包的作用域以及闭包案列的介绍:

    转载▼ 标签: it   js闭包的作用域以及闭包案列的介绍:   首先我们根据前面的介绍来分析js闭包有什么作用,他会给我们编程带来什么好处? 闭包是为了更方便我们在处理js函数的时候会遇到以下的几 ...

  3. 大部分人都会做错的经典JS闭包面试题

    由工作中演变而来的面试题 这是一个我工作当中的遇到的一个问题,似乎很有趣,就当做了一道题去面试,发现几乎没人能全部答对并说出原因,遂拿出来聊一聊吧. 先看题目代码: function fun(n,o) ...

  4. Js闭包常见三种用法

        Js闭包特性源于内部函数可以将外部函数的活动对象保存在自己的作用域链上,所以使内部函数的可以将外部函数的活动对象占为己有,可以在外部函数销毁时依然存有外部函数内的活动对象内容,这样做的好处是可 ...

  5. js闭包之初步理解( JavaScript closure)

    闭包一直是js中一个比较难于理解的东西,而平时用途又非常多,因此不得不对闭包进行必要的理解,现在来说说我对js闭包的理解. 要理解闭包,肯定是要先了解js的一个重要特性, 回想一下,那就是函数作用域, ...

  6. (原创)JS闭包看代码理解

    <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="C ...

  7. js闭包理解

    js闭包的作用是使函数外可以访问函数内部的变量,是通过 在函数内部 定义 访问函数内变量 的函数实现的,内部的一个函数产生一个闭包 function a() { var i=0; return fun ...

  8. js闭包理解实例小结

    Js闭包 闭包前要了解的知识  1. 函数作用域 (1).Js语言特殊之处在于函数内部可以直接读取全局变量 <script type="text/javascript"> ...

  9. <一>初探js特效魅力之全选不选反选04

    初探js特效魅力04 我们在进入到公司里面工作的时候,做一个同一个项目,经常是大家分工合作,当我们写css时,一般不写在行间,因为这样会被误操作,也就是被乱删了都不知道,这样的后果是很难检查的 ,因为 ...

随机推荐

  1. 洛谷P1258 小车问题

    题目描述 甲.乙两人同时从A地出发要尽快同时赶到B地.出发时A地有一辆小车,可是这辆小车除了驾驶员外只能带一人.已知甲.乙两人的步行速度一样,且小于车的速度.问:怎样利用小车才能使两人尽快同时到达. ...

  2. poj3648,2-sat求解

    关键是题意的理解,英语,有时候明明每个字都认识,但是还是理解错误!哎!!悲剧啊!题意啊! 这是关键!开始误理解为n对新娘郞,非也!是只有一对,其他是夫妇,理解后就好做了,建立图 是关键,怎么转化关系, ...

  3. HDU 5695 Gym Class

    拓扑排序. #include<cstdio> #include <iostream> #include<cstring> #include<cmath> ...

  4. React学习及实例开发(二)——用Ant Design写一个简单页面

    本文基于React v16.4.1 初学react,有理解不对的地方,欢迎批评指正^_^ 一.引入Ant Design 1.安装antd yarn add antd 2.引入 react-app-re ...

  5. 洛谷——P2256 一中校运会之百米跑

    P2256 一中校运会之百米跑 题目背景 在一大堆秀恩爱的**之中,来不及秀恩爱的苏大学神踏着坚定(?)的步伐走向了100米跑的起点.这时苏大学神发现,百米赛跑的参赛同学实在是太多了,连体育老师也忙不 ...

  6. S5700&S5710 产品文档 : 配置

    http://support.huawei.com/hdx/hdx.do?docid=SC0000699332&lang=zh&path=PBI1-C103367%2FPBI1-C10 ...

  7. 初探无线安全审计设备WiFi Pineapple Nano系列之PineAP

    前言: 之前曾经介绍过国外无线安全审计设备The WiFi Pineapple Nano的SSLsplit模块和ettercap模块及实验. 在玩WiFi Pineapple Nano 设备的过程中, ...

  8. ArcGIS Engine 10.2 如何发布服务

    http://blog.csdn.net/arcgis_all/article/details/17376397 1 ArcGIS Engine 10.2 如何发布服务 ArcGIS Engine的代 ...

  9. 【APUE】进程间通信之共享存储(mmap函数)

    共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式,因为进程可以直接读写内存,而不需要任何数据的拷贝.对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只 ...

  10. Dell R420 RAID建立以及系统安装

    http://thefallenheaven.blog.51cto.com/450907/1753472 Dell R420的RAID划分,以及系统安装 3块2T的盘,装好硬盘后开机,这里有3种方式去 ...