浅谈JavaScript中的闭包


在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量。

创建一个闭包的常用的方式:在一个函数内部创建另一个函数。
比如:

 function compareByProperty(propertyName){
returnfunction(obj1,obj2){
return obj1[propertyName] - obj2[propertyName];
}
}
 
该例中,compareByProperty内部的匿名函数有权利访问compareByProperty函数中的活动变量。
 
调用:
 var compareNames = compareByProperty("name");
var result = compareNames({name:"jack"},{name:"rose"});// < 0
在compareByProperty()执行完之后,其活动对象不会被销毁,这是因为匿名函数的作用域链仍在引用这个活动对象。也就是说:当compareByProperty()函数返回之后,其本身执行环境的作用域会被销毁,但是它的活动对象仍留在内存中,供匿名函数使用。直到这个匿名函数被销毁了,这个活动对象才会被销毁。
所以,当执行:
compareNames = null;
之后,解除掉了匿名函数,compareByProperty()的活动对象也随之被销毁。
下图展示了调用compareNames()时产生的作用域链:
 
 
1、闭包与变量:
思考一下这样一个问题:
 function createFunction(){
var func =newArray();
vari;
for(i=0;i<10;i++){
func[i]=function(){
return i;
};
}
return func;
}
你可能会觉得func数组里面的函数应该返回其对应的索引值,
比如你觉得下面这些代码的执行结果是:0-9
 var funArr = createFunction();
var i;
for(i=0;i<funArr.length;i++){
console.log(funArr[i]());
}
(我强烈建议你在你的浏览器中执行一下这些代码)。
 
但是,很不幸,它们每一个都返回10,不用觉得不科学,这和我们日常的思维习惯不同。
请注意:闭包的作用域链保存的是包含这个闭包的活动对象。
也就是说,func里面的每一个元素,其作用域链保存(或者说“引用”更为恰当)的都是 createFunction()这个函数的活动对象(其中包括 i )
每一次循环,i 都会变化,最后返回createFunction()返回时,i 的值是10,看到这里,如果你真的理解了,那么你就知道,为什么func里面的每一个元素调用后都是返回10.
 
如果将代码改变一下,结果就完全不一样了:
 function createFunction(){
var func =newArray();
var i;
for(i =0; i<10;i++){
func[i]=function(num){
returnfunction(){
return num;
}
}(i);
}
return func;
}
 
在上面的代码中,我们不将一个匿名函数赋值给func[i],而是立即调用一个匿名函数,然后将这个匿名函数的返回值(也是一个匿名函数) 赋值给func[i],这样做能达到我们预想的效果(func的每一个元素调用后的返回值都是其对应的下标)的原因是:我们传入了变量i,由于函数参数是值传递的,所以变量i的值会被复制给参数num,而在这个匿名函数内部,创建了一个闭包,这个闭包访问的是包含它的那个函数的活动变量(num),这样一来,func数组里面的每一个元素调用后都会得到一个自己的num变量的副本,所以就可以返回各自对应的num的值了。
 
2、闭包中的this对象(为什么又是this!!!)
看一个例子:
 var name = "The window";
var myObj = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
}
}
}
console.log(myObj.getNameFunc()()); //非严格模式下
 
程序运行的结果是在控制台打印出"The window";
为什么?
 
我们看这一句:myObj.getNameFunc()(),拆解一下:
var a = myObj.getNameFunc();
a();
 
当调用myObj.getNameFunc()时,其作用域是myObj这个对象,它返回了一个闭包,我们将这个闭包赋值给a
当调用a时,其作用域不再是 myObj这个对象了,这次我们是在window这个对象中用它,这个时候,由于闭包的特性(访问包含这个闭包的那个函数的活动变量),this就指向window这个对象,而this.name自然就是指在全局定义的"The window"。
 
我们把代码改一下:
 var name = "The window";
var myObj = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
}
}
}
console.log(myObj.getNameFunc()()); //非严格模式下
在这里,调用myObj.getNameFunc()时,作用域是myObj这个对象,它先是将this(即myObj)赋值给 that
然后,返回一个闭包,我们将这个闭包赋值给b。前面我们提到,函数getNameFunc()返回之后,它自身的作用域会被销毁,但是,由于存在闭包仍然在引用着它的活动变量,所以,这个来自于getNameFunc()的活动变量(this)并不会被销毁,而是一直保留在内存中,供闭包使用,直到闭包被销毁(如:赋值为null),再没有别的闭包引用这个活动变量,这个活动变量才会被垃圾回收。这样,当调用b时,访问到的that.name,是来自于myObj的。
 
总之:如果想访问this 或者 是arguments对象,必须要将这两个对象的引用保存到另一个闭包能访问到变量中。

浅谈JavaScript中的闭包的更多相关文章

  1. 浅谈JS中的闭包

    浅谈JS中的闭包 在介绍闭包之前,我先介绍点JS的基础知识,下面的基础知识会充分的帮助你理解闭包.那么接下来先看下变量的作用域. 变量的作用域 变量共有两种,一种为全局变量,一种为局部变量.那么全局变 ...

  2. 浅谈JavaScript中的null和undefined

    浅谈JavaScript中的null和undefined null null是JavaScript中的关键字,表示一个特殊值,常用来描述"空值". 对null进行typeof类型运 ...

  3. 浅谈JavaScript中的正则表达式(适用初学者观看)

    浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ...

  4. 浅谈JavaScript中闭包

    引言 闭包可以说是JavaScript中最有特色的一个地方,很好的理解闭包是更深层次的学习JavaScript的基础.这篇文章我们就来简单的谈下JavaScript下的闭包. 闭包是什么? 闭包是什么 ...

  5. 浅谈JavaScript中的内存管理

    一门语言的内存存储方式是我们学习他必须要了解的,接下来让我浅谈一下自己对他的认识. 首先说,JavaScript中的变量包含两种两种类型: 1)值类型或基本类型:undefined.null.numb ...

  6. 浅谈JavaScript中的继承

    引言 在JavaScript中,实现继承的主要方式是通过原型链技术.这一篇文章我们就通过介绍JavaScript中实现继承的几种方式来慢慢领会JavaScript中继承实现的点点滴滴. 原型链介绍 原 ...

  7. 浅谈JavaScript中的this

    引言 JavaScript 是一种脚本语言,因此被很多人认为是简单易学的.然而情况恰恰相反,JavaScript 支持函数式编程.闭包.基于原型的继承等高级功能.本文仅采撷其中的一例:JavaScri ...

  8. 浅谈JavaScript中继承的实现

    谈到js中的面向对象编程,都有一个共同点,选择原型属性还是构造函数,两者各有利弊,而就片面的从js的对象创建以及继承的实现两个方面来说,官方所推荐的是两个相结合,各尽其责,各取其长,在前面的例子中,我 ...

  9. 【总结】浅谈JavaScript中的接口

    一.什么是接口 接口是面向对象JavaScript程序员的工具箱中最有用的工具之一.在设计模式中提出的可重用的面向对象设计的原则之一就是“针对接口编程而不是实现编程”,即我们所说的面向接口编程,这个概 ...

随机推荐

  1. P1941 飞扬的小鸟

    此题很容易写出方程,由以前的知识可以迁移得,本题可以用完全背包的方法进行优化,使用滚动数组即可得到答案. //莫名奇妙60分.不知道什么细节出了错. #include <bits/stdc++. ...

  2. Android WebView常见问题及解决方案汇总

    Android WebView常见问题解决方案汇总: 就目前而言,如何应对版本的频繁更新呢,又如何灵活多变地展示我们的界面呢,这又涉及到了web app与native app之间孰优孰劣的争论. 于是 ...

  3. Caffe配置简明教程 ( Ubuntu 14.04 / CUDA 7.5 / cuDNN 5.1 )

    1. 前言 本教程使用的系统是Ubuntu 14.04 LTS 64-bit,使用的CUDA版本为7.5,使用的NVIDIA驱动版本为352. 如果您使用的Pascal架构显卡,如GTX1080或者新 ...

  4. 学习OpenCV——SVM 手写数字检测

    转自http://blog.csdn.net/firefight/article/details/6452188 是MNIST手写数字图片库:http://code.google.com/p/supp ...

  5. <<卸甲笔记>>-基础语法对比

    以Oracle中sottt用户下的数据为例,PPAS 中scott用户下面的数据由Oracle迁移而来 1 查询emp表中的数据 Oracle [root@test03 ~]# su -  oracl ...

  6. Java位运算符

    & 两个二进制数的相同位比较,都为1,结果为1,否则结果为0. | 两个二进制数的相同位比较,只要有一个为1,结果就为1,否则为0. ~ 对一个二进制数的每一位取反,原值为1,取反为0,原值为 ...

  7. 一个IP能建立的最大连接数是多少?

    在探讨这个问题前,我们先假设一种经典的连接模型: Client -> Load Balancer-> RealServer Pool 并且我们假设这里使用NAT模式的负载均衡,在这种模式下 ...

  8. List,Set,Map用法以及区别(转)

    Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素.一些Collection允许相同的元素而另一些不行.一些能排序而另一些不行.Java ...

  9. 【转】PowerShell入门(二):PowerShell是Cmd命令行的加强版吗?

    转至:http://www.cnblogs.com/ceachy/archive/2013/01/31/PowerShell_vs_Cmd.html PowerShell是命令行的加强版吗?Power ...

  10. 机器学习实战-边学边读python代码(4)

    程序2-4 分类器针对约会网站的测试代码(4) def datingClassTest():hoRatio = 0.10 //将文件读入内存矩阵datingDataMat,datingLabels = ...