学习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中的闭包解析的更多相关文章

  1. 让你分分钟学会Javascript中的闭包

    Javascript中的闭包 前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它 ...

  2. Javascript中的闭包(转载)

    前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它.下面是作者从作用域链慢慢讲到 ...

  3. 狗日的Javascript中的闭包

    前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它.下面是作者从作用域链慢慢讲到 ...

  4. 难道这就是JavaScript中的"闭包"

    其实对于JavaScript中的"闭包"还没真正理解,这次在实际Coding中似乎遇到了"闭包"的问题,仅此摘录,以待深究. 表现为jQuery的post方法回 ...

  5. 浅谈JavaScript中的闭包

    浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...

  6. JavaScript中的闭包理解

    原创文章,转载请注明:JavaScript中的闭包理解  By Lucio.Yang 1.JavaScript闭包 在小学期开发项目的时候,用node.js开发了服务器,过程中遇到了node.js的第 ...

  7. 【JS】JavaScript中的闭包

    在JavaScript中,闭包指的是有权访问另一个函数作用域中的变量的函数:创建闭包最常见的方式就是在一个函数内创建另一个函数.如下例子: function A(propertyName){ retu ...

  8. [译]Javascript中的闭包(closures)

    本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU& ...

  9. javaScript中的闭包原理 (译)

    这篇文章通过javaScript代码解释了闭包的原理,来让编程人员理解闭包.它不是写给大牛或使用功能性语言进行编程的程序员的.一旦意会了其核心概念,闭包理解起来并不难.然而,你不可能通过阅读任何有关闭 ...

随机推荐

  1. iOS开发 弹簧效果

    #import "DDJelloView.h" #define SYS_DEVICE_WIDTH    ([[UIScreen mainScreen] bounds].size.w ...

  2. [ubuntu14.04 amd64 ]搜狗拼音輸入法安裝

    这个网址下载之后,双击下载的deb文件http://mirrors.sohu.com/deepin/pool/non-free/f/fcitx-sogoupinyin-release/ 就会在ubun ...

  3. Docker中的镜像分层技术详解

    早在集装箱没有出现的时候,码头上还有许多搬运的工人在搬运货物,在集装箱出现以后,码头上看到更多的不是工人,而且集装箱的搬运模式更加单一,更加高效,还有其他的好处,比如:货物多打包在集装箱里面,可以防止 ...

  4. telnet: connect to address xxxxxxx: No route to host

    在要连接的服务上执行iptables -F

  5. javascript复习总结

    改变HTML内容:document.getElementById(id).innerHTML = new HTML; 改变HTML属性:document.getElementById(id).inne ...

  6. Yii MySQL修改数据库的数据

    最新学习Yii框架,分享一些学习心得,适合初学者,大神请按ctrl + w //第一种方法 <?php /* * $id 代表主键,可以是一个也可以是一个集合. * $attributes 代表 ...

  7. [转载]MySQL将DateTime时间类型格式化

    DATE_FORMAT(date,format)  根据format字符串安排date值的格式.   select from_unixtime(time,'%Y-%m-%d %H:%i:%s');   ...

  8. 【转载】VMware虚拟机修改硬盘容量大小

    很多人在安装虚拟机系统的时候,为了节省硬盘空间,把硬盘容量设置得较小,可是后来发现硬盘容量不够用了.在VMware中又不能直接修改虚拟机的硬盘容量大小,或者重建虚拟机系统,非常麻烦. 其实在VMwar ...

  9. CodeForces 688D-Remainders Game

    题意: 已知n, k与n个整数(c1,c2,...,cn),问你是否存在一个数x,使得它能被n个整数且k整除. 分析: 可以先将n个整数的最小公倍数lcm计算出来,再判断它是否能被k整除. 代码如下: ...

  10. leetcode 日记 3sumclosest java

    思路一为遍历: public int thirdSolution(int[] nums, int target) { int result = nums[0] + nums[1] + nums[2]; ...