谈到闭包,人们常常会把匿名函数和闭包混淆在一起。闭包是指由权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数,仍以前面的

createComparisonFunction()函数为例

  

           function createComparisonFunction(propertyName){
return function(object1,object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if(value1<value2){
return -1;
}else if(value1>value2){
return 1;
}else{
return 0;
}
}
};

  在标识的部分,它访问了外部的变量 propertyName 即使这个函数被返回后,仍然可以访问到这个变量(propertyName);这是应为 匿名函数作用域链中包含  createComparisonFunction() 的作用域。

要理解必须掌握作用域的几个概念

  作用域链:

    什么时候会生成?:当代码在一个执行环境中执行时,就会创建变量对象的一个作用域链。

    作用:保证对执行环境有权访问的所以函数和变量的有序访问。作用域的前端永远是当前的执行环境所对应的变量对象;

  执行环境:定义了变量或函数有权访问其他数据,决定它们各自的行为。 每个环境都有一个与之对应的变量对象(variable object)。环境中定义的变量和函数都保存在这个对象中。 当函数执行完成后其执行环境就会被销毁

  变量对象:保存执行环境中的变量和函数。

  活动对象:如果执行环境是函数,则将其活动对象作为变量对象。活动对象在最开始时只包含一个变量。

在函数执行过程中,为读取和写入变量的值,就需要的作用域链中查找对应的变量。先看看一个实例来了解下每个概念对应部分:

  function compare(value1,value2){
 
if(value1<value2){
return -1;
}else if(value1>value2){
return 1;
}else{
return 0;
}
}
   var result = compare(5,10);
  

   

  先定义了 compare 函数,后又在全局作用域中调用,在这个compare 执行环境为函数的时候,当前活动对象则为变量对象。 活动对象默认是只有 arguments 但是此时却不一样(this,arguments,value1,value2);

而全局作用域中对应变量对象(compare 、result);来看看下图吧!

  <1>在定义compare函数的时候,会创建一个预先包含全局变量对象作用域链,这个作用域链保存在内部的[[Scope]]属性中。

  <2>当在调用 compare 函数的时候,会为函数创建一个执行环境,然后通过赋值函数的[[Scope]]属性中的对象构建起执行环境的作用域链。此后,又有一个活动对象被创建并推入执行环节作用域链的前端。

对于compare函数的执行环境而言,其作用域链中包含两个变量对象(本地活动对象和全局变量对象)。显然,作用域链本质上是一个指向变量对象的指针列表,它引用但不实际包含变量对象。

所以无论什么时候,访问一个变量时都会从作用域链中搜索具有相应名字的变量。一般来讲当函数执行完毕后。局部活动对象就会被销毁,内存中仅保存全局作用域。但是闭包所有不同。

  在闭包中,当函数内部定义一个内部函数,该内部函数会把外部函数的活动对象添加到自己的作用域链中;因此createComparisonFunction()定义的匿名函数,其作用于域会包含外部函数的作用域。

 1           function  createComparisonFunction(propertyName){
2 return function(object1,object2){
3 var value1 = object1[propertyName];
4 var value2 = object2[propertyName];
5 if(value1<value2){
6 return -1;
7 }else if(value1>value2){
8 return 1;
9 }else{
10 return 0;
11 }
12 }
13 };

当下面代码执行时,外部函数与内部函数包含的作用域链, 如下图

 var compare = createComparisonFunction("name");
var result = compare({name:"Nicholas"},{name:"Greg"});

在代码执行过程中,用变量 compare 保存了其返回的内部匿名函数,而作用域链中包含了三个变量对象,(全局变量对象,外部函数-活动对象,匿名函数-活动对象);

所以即使返回后,也还是可以访问到对应的变量; 因为外部函数(createComparisonFunction) 执行完成时,其活动对象依然存在,并不会销毁,因为其被内部函数作用域链中引用了;

虽然 外部函数返回到,其执行环境对应作用域链被销毁,但是其活动对象依然存在。直到匿名函数被销毁,其createComparisonFunction对应的活动对象才会被销毁。

 var compare = createComparisonFunction("name");
var result = compare({name:"Nicholas"},{name:"Greg"});
compare = null; //主要是手动赋值为空,通知系统 进行垃圾处理; 随着其作用域链被销毁(除全局作用域链之外)。

由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内部占用过多。

JavaScript 函数之 ------------------ 闭包的更多相关文章

  1. JavaScript函数、闭包、原型、面向对象

    JavaScript函数.闭包.原型.面向对象 断言 单元测试框架的核心是断言方法,通常叫assert(). 该方法通常接收一个值--需要断言的值,以及一个表示该断言目的的描述. 如果该值执行的结果为 ...

  2. javaScript函数与闭包

    js中函数也是对象,具有一切对象的特征,可以作为表达式给变量赋值,可以作为函数的形参,或者函数的返回值,函数内可以嵌套函数等等,函数内以声明方式定义的函数是局部函数,用表达式声明的函数则由赋值变量的性 ...

  3. JavaScript函数及闭包

    前面一片文章讲到过一点函数,了解到每声明一个函数就会产生一个作用域.而外面的作用域访问不了里面的作用域(把里面的变量和函数隐藏起来),而里面的可以访问到外面的.对于隐藏变量和函数是一个非常有用的技术. ...

  4. javascript函数闭包(closure)

    一,首先感受下javascript函数的闭包 二,闭包 1,定义:闭包就是能够读取其他函数内部变量的函数,由于在javascript语言中,只有在函数内部的子函数才能够读取局部变量,因此可以把闭包简单 ...

  5. JavaScript函数之作用域 / 作用链域 / 预解析

    关于作用域和作用链域的问题,很多文章讲的都很详细,本文属于摘录自己觉得对自己有价值的部分,留由后用,仅供参考,需要查看详细信息请点击我给出的原文链接查看原文件 做一个有爱的搬运工~~ -------- ...

  6. JavaScript权威设计--命名空间,函数,闭包(简要学习笔记十二)

    1.作为命名空间的函数 有时候我们需要声明很多变量.这样的变量会污染全局变量并且可能与别人声明的变量产生冲突. 这时.解决办法是将代码放入一个函数中,然后调用这个函数.这样全局变量就变成了 局部变量. ...

  7. 深入理解javascript函数参数与闭包(一)

    在看此文章,希望先阅读关于函数基础内容 函数定义与函数作用域 的章节,因为这篇文章或多或少会涉及函数基础的内容,而基础内容,我放在函数定义函数作用域 章节. 本文直接赘述函数参数与闭包,若涉及相关知识 ...

  8. 深入理解javascript原型和闭包(2)——函数和对象的关系

    上文(理解javascript原型和作用域系列(1)——一切都是对象)已经提到,函数就是对象的一种,因为通过instanceof函数可以判断. var fn = function () { }; co ...

  9. JavaScript中的闭包和匿名函数

    JavaScript中的匿名函数及函数的闭包   1.匿名函数 2.闭包 3.举例 4.注意 1.匿名函数 函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数:就是没 ...

随机推荐

  1. how to count uv area

    先放着,空了再整理.... fn getModeUvVolumetric mode chang= ----得到UV使用率( --global facesNumSum = meshop.getnumfa ...

  2. nutch Fetcer阶段详解

    job.setSpeculativeExecution(false); 抓网页阶段,不允许同一个任务运行多次,否则,网页就抓重了 为了充分利用闲置资源,加快map 和 reduce 的执行,于是有Sp ...

  3. zoj 3785 What day is that day?

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5272 打表找规律. #include <cstdio> #incl ...

  4. Windows 7 mklink命令详解

    mklink是Windows 7下的一个类似于linux下In的命令,其作用是在NTFS文件系统中创建文件或目录的链接(类似于桌面快捷方式).如果加以利用其发挥的作用是非常的大的,不仅可以帮助我们节省 ...

  5. 【转】android开发 dts、各种接口porting----不错

    原文网址:http://www.xuebuyuan.com/1023185.html 1. repo init -u git://review.sonyericsson.net/platform/ma ...

  6. .NET开发者需要的工具箱

    本文作者 Spencer 是一名专注于 ASP.NET 和 C# 的程序员,他列举了平时工作.在家所使用的大部分开发工具,其中大部分工具都是集中于开发,当然也有一些其它用途的,比如图片处理.文件压缩等 ...

  7. javascript对象拷贝

    浅拷贝 浅拷贝函数: function copy(p){ var c = {}; for (var i in p){ c[i] = p[i]; } c.uber = p; return c; } 测试 ...

  8. POJ1163——The Triangle

    Description 73 88 1 02 7 4 44 5 2 6 5 (Figure 1) Figure 1 shows a number triangle. Write a program t ...

  9. Matchers and assertthat

    assertThat的一般句型为: assertThat([value],[matcher statement]); 这种断言的优点有: 1.更具有可读性:该语法允许我们以“主谓宾”的方式来思考(as ...

  10. php中的后期静态绑定("Late Static Binding")

    在我们以往中,在类中使用self关键字的时候都是指向了被调用方法定义时的类,而非原始的调用类. 例如: class Animal{ static $IQ_lv_avg = 1; public stat ...