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

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. PHP之路——PHPExcel使用

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABGMAAAJkCAIAAAA6GnvRAAAgAElEQVR4nOzd918bV/ov8Pv33Y2RNC

  2. iOS开发网络篇—XML数据的解析

     iOS开发网络篇—XML数据的解析 iOS开发网络篇—XML介绍 一.XML简单介绍 XML:全称是Extensible Markup Language,译作“可扩展标记语言” 跟JSON一样,也是 ...

  3. 转:基于科大讯飞语音API语音识别开发详解

    原文来自于: http://www.52wulian.org/android_voice/ 最近项目需要用到android语音识别,立马就想到科大讯飞,结合官方实例及阅读API文档,初步的完成了And ...

  4. Intra Chroma Prediction

    帧内预测依赖于当前宏块的相邻宏块,如果任何一个相邻宏块不可用,那么会直接影响到当前宏块的预测方式. 那么宏块怎么才谓之可用? 满足以下几个条件的相邻宏块为不可用: 相邻宏块超出边界,即(x<0 ...

  5. 【转】两分钟彻底让你明白Android Activity生命周期(图文)!----不错

    原文网址:http://blog.csdn.net/android_tutor/article/details/5772285 大家好,今天给大家详解一下Android中Activity的生命周期,我 ...

  6. Word Ladder——LeetCode

    Given two words (start and end), and a dictionary, find the length of shortest transformation sequen ...

  7. SRM593(1-250pt,500pt)

    SRM 593 DIV1 250pt 题意:有如下图所示的平面,每个六边形有坐标.将其中一些六边形染色,要求有边相邻的两个六边形不能染同一种颜色.给定哪些六边形需要染色,问最少需要多少种颜色. 解法: ...

  8. Unity中OnGUI绘制贪吃蛇

    Square.cs : public class Square : MonoBehaviour { public int row, col; public Rect rect; public Text ...

  9. windows 编程 —— 子窗口类别化(Window Subclassing)

    对于子窗口控件,有时我们可能会想要获取子窗口的某些消息,比如在一个主窗口下有三个按钮,如果想要实现使用键盘Tab或者Shift-Tab键来使焦点切换于不同按钮之间,这时就可以使用子窗口类别化(Wind ...

  10. 705 - Slash Maze

    By filling a rectangle with slashes (/) and backslashes ( ), you can generate nice little mazes. Her ...