javascript中的闭包解析
学习javaScript已经有一段时间了,在这段时间里,已经感受到了JavaScript的种种魅力,这是一门神奇的语言,同时也是一门正在逐步完善的语言,相信在大家的逐步修改中,这门语言会逐步的完善下去,在上一篇随笔中,和大家分享了JavaScript中独有的类中的继承方式,今天呢,就跟大家分享一下我这几天一直在搞,却还是搞的不是很透彻的闭包问题,对于一个初学者而言,JavaScript中的闭包无疑是一个难点,而且也是我们必须要掌握的一个重点,那么今天我就跟大家分享一下我在学习闭包的时候的感悟以及相应的理解,首先,我们在一个函数中有一个变量: 代码1
1 function people(){
var age = 12;//函数中有一个变量
( function (){ //在函数中我们再定义一个自调用函数
alert(age);
})();
}
在函数people中,有着变量age,大家应该之前都有了解到JavaScript中特有的变量作用域的问题,函数本身就是一个作用域,函数里边可以访问外边的变量,而函数外边并不能访问函数里边的变量,这样,我们就遇到了一个问题,如果我们想要获取函数中的变量age怎么办?如代码1中所示,因为自调用函数在people中,所以它可以访问它外边的变量,所以自调用函数可以访问age,那么我们就想,将这个自调用函数return出来不就行了吗?代码2:
function people(){
var age = 12;
return function (){
alert(age);
}
}
var xiaoMing = new people();
xiaoMing();//会弹出文本框12,说明在people外边调用到了内部变量age
好了,通过这种方法,我们获得了函数内部的变量,那么这就叫做闭包(closure),上边的功能就是它的第一个功能,可以在函数外部通过闭包获得函数内部的变量,从形状上看,闭包就是函数里边再定义一个函数并返回,从书上以及各个博客上看到了对闭包的解释各种各样,我对闭包的理解而言,整个函数就相当于一个房子,这个房子没有门,只有一个天窗,我们在下边无法看见房子里边放的东西,而闭包就像是一个梯子,让我们爬上去可以通过天窗看到房子里边放的东西,就是连接函数外边和里边的一座桥梁,闭包对于我们的便利性是不言而喻的,然而,事物总是有着相反的一面,闭包有他的好,当然也有它的坏,现在,我们可以先用闭包做一个累加的例子:代码3:
function func(){
var count=10;
return function(){
return ++count;
}
}
var ss = new func();
alert(ss());//弹出11
alert(ss());//弹出12
通过代码3我们可以看出,每次调用func中返回的闭包时,count是在累加的,这时我们心中肯定就会有很多疑惑,不是说好的函数是一个作用域吗?执行完了函数func它体内的变量应该不存在了呀?怎么每次调用的时候它都在累加呢?这就是闭包的第二个作用了,当闭包在函数体外执行时,它的体内保存了原来算是它的父类的函数的整个执行环境以及它体内调用的变量,这时他们的关系就像我们盖房子一样,func就像地基一样,ss就是我们的房顶,这时我们站在房顶上,那么地基会消失吗?显然是不能的,这时闭包的一个优点,同时也算是它的一个缺点,就是它将一个内部变量一直放到了内存中释放不了,有可能会造成内存泄露,但这也是它的一个优点,可以将作用域链拉长,但这个功能在for循环中是一个经常出错的地方:
代码4:
function func(){
var arr=[];
for (var i=0;i<5;i++){
arr[i]=function (){//注意此处,往数组中存放的是一个函数
return i;
}
}
return arr;
}
var arr=func();
for(var i=0;i<5;i++){
console.log(arr[i]());//这时会返回五个5
}
这时我们是否也会感到同样的疑惑,这不是应该返回0-4吗?这正是闭包在应用中的一个坑,这时,我们可以这样理解,当往arr[0]中存放第一个闭包函数时,函数并没有执行,那么这时闭包中就存放了i的一个链接,它也不知道i的值是多少,当func执行完了,这时闭包中存放在i的一个作用域链接,当执行arr数组中的函数时,由于数组中的函数没有i这个变量,所以它要向上一级去寻找,这时,它就找到了func中,而此时func中i的值已经变为5了,所以输出的每一个数都是5.那么有因就有果,有好就有坏,有错误我们就有方法去解决:
function func(){
var arr=[];
for (var i=0;i<5;i++){
arr[i]=(function (num){
return i;
})(i);//这时使用自调用函数
}
return arr;
}
var arr=func();
for(var i=0;i<5;i++){
console.log(arr[i]);//这时会输出0-4
}
修改的方法一:就是将闭包改为一个自调用函数这时,传入arr[i]中的不再是一个函数,而是传入的参数i,以此类推,我们还可以返回一个闭包,只不过要让闭包中存放一个确定的值,而不再是一个变量:
function func(){
var arr=[];
for (var i=0;i<5;i++){
arr[i]=function (num){
return function(){
return num;
}
}(i);
}
return arr;
}
var arr=func();
for(var i=0;i<5;i++){
console.log(arr[i]());//这时会输出0-4
}
使用这种方案的时候,用新创建的函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变,所以在使用闭包时,尽量不要将后续会发生变化的变量放到闭包中.同时,闭包不仅会改变函数中的变量的使用范围变广,它同时也会改变this的作用域:
var name="kkkk";
function People(){
this.name="lala",
this.getName=function(){
return function(){
alert(this.name)
};
}
}
var xiaoMing=new People();
xiaoMing.getName()();//这时会弹出kkkk
这时,当我们返回一个闭包时,它当中存放的this绑定的对象是window,而不是People,其中的原理:我的理解就是,当你返回一个函数时,它其中的this是封闭在其中的那时候还没有执行函数,所以this的指向还没有确定,当在对象外执行闭包时,this回去找它要指向的对象,这时它就会指向window,我们可以用that来捕获this:
var name="kkkk";
function People(){
this.name="lala",
this.getName=function(){
var that=this;
return function(){
alert(that.name)
};
}
}
var xiaoMing=new People();
xiaoMing.getName()();
这时再输出就是lala了,当然,我们不仅可以使用这种方式来捕获this,我们还可以使用之前所学的对象冒充的方法来执行函数:
var name="kkkk";
function People(){
this.name="lala",
this.getName=function(){
return function(){
alert(this.name)
};
}
}
var xiaoMing=new People();
xiaoMing.getName().apply(xiaoMing,[]);
使用这种方式同样可以达到我们想要的目的,同时,我们使用call也是可以的.到了这里,大家应该对闭包有了一个初步的了解吧,闭包这种东西,可能理解的时候好理解一些,但是当我们实际应用的时候,刚开始可能会感觉到十分的吃力,但我们应该相信,熟能生巧,而且闭包这种东西,可能我们每天都在用,可对于它内在的原理还是一知半解,这个一定要多做练习,多做实验,当你有疑问的时候,就把代码打下来去运行一下,看一下结果,再想一下为什么会是这种结果,大家,一起加油!
本博文是博主原创,如有转载请说明出处!
javascript中的闭包解析的更多相关文章
- 让你分分钟学会Javascript中的闭包
Javascript中的闭包 前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它 ...
- Javascript中的闭包(转载)
前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它.下面是作者从作用域链慢慢讲到 ...
- 狗日的Javascript中的闭包
前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它.下面是作者从作用域链慢慢讲到 ...
- 难道这就是JavaScript中的"闭包"
其实对于JavaScript中的"闭包"还没真正理解,这次在实际Coding中似乎遇到了"闭包"的问题,仅此摘录,以待深究. 表现为jQuery的post方法回 ...
- 浅谈JavaScript中的闭包
浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...
- JavaScript中的闭包理解
原创文章,转载请注明:JavaScript中的闭包理解 By Lucio.Yang 1.JavaScript闭包 在小学期开发项目的时候,用node.js开发了服务器,过程中遇到了node.js的第 ...
- 【JS】JavaScript中的闭包
在JavaScript中,闭包指的是有权访问另一个函数作用域中的变量的函数:创建闭包最常见的方式就是在一个函数内创建另一个函数.如下例子: function A(propertyName){ retu ...
- [译]Javascript中的闭包(closures)
本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU& ...
- javaScript中的闭包原理 (译)
这篇文章通过javaScript代码解释了闭包的原理,来让编程人员理解闭包.它不是写给大牛或使用功能性语言进行编程的程序员的.一旦意会了其核心概念,闭包理解起来并不难.然而,你不可能通过阅读任何有关闭 ...
随机推荐
- 20160824_CentOS6.4x64_关闭IPv6
1.参考网址: http://blog.csdn.net/suplxj/article/details/7773423 2.我的操作: #cat <<EOF>>/etc/mod ...
- express-generator安装时出错,最后用VPS解决
npm install -g express-generator npm ERR! Linux 3.10.0-229.el7.x86_64npm ERR! argv "/usr/local/ ...
- JS只弹出一个居中弹出窗口
var newWindow;//定义一个窗口,有利于窗口间的通讯function makeNewWindow(url) { if (!newWindow || newWindow.closed) ...
- iOS开发UI篇—Quartz2D使用(信纸条纹)
iOS开发UI篇—Quartz2D使用(信纸条纹) 一.前导程序 新建一个项目,在主控制器文件中实现以下几行代码,就能轻松的完成图片在视图中的平铺. #import "YYViewContr ...
- Fireeye火眼公司发布报告,评论中国网络间谍活动
2013年10月2日,Fireeye火眼公司发布报告,评论中国网络间谍活动-Fireeye(美 国火眼公司)发布报告<世界网络大战:理解网络攻击背后的国家意图>(World War C: ...
- bzoj 3131: [Sdoi2013]淘金
#include<cstdio> #include<iostream> #include<queue> #include<algorithm> #def ...
- BestCoder Round #41
T1:ZCC loves straight flush(hdu 5228) 题目大意: 给出5张牌,问至少替换多少张牌可以构成同花顺. 题解: 1.直接枚举所有同花顺(枚举花色A-D和最小的数字1-1 ...
- 局域网单机部署双tomcat内外网不能访问防火墙问题查出来
tomcat部署的项目内网访问不了 win7 64 位 控制面板 - 安全 -防火墙-入站规则- 新建规则 选中“端口”按钮,点选“下一步”: 选择“TCP”按钮,在“特定本地端口”输入tomcat ...
- java中判断一个字符串是否“都为数字”和“是否包含数字”和“截取数字”
在javascript中有一个方法isDigit()使用来判断一个字符串是否都是数字,在java的字符串处理方法中没有这样的方法,觉得常常需要用到,于是上网搜了一下,整理出了两个用正则表达式匹配的判断 ...
- 2016 - 1 - 24 NSURLSession (一)
一: NSURLSession简介 1.实施步骤 1.1 使用 NSURLSession对象 创建TASK ,然后执行TASK 2.TASK的类型: 二: NSURLSession的简单使用: - ( ...