JavaScript 函数之 ------------------ 闭包

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

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                 };

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

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

  作用域链:

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

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

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

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

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

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

 1  function compare(value1,value2){
 2  
 3     if(value1<value2){
 4         return -1;
 5     }else if(value1>value2){
 6         return 1;
 7     }else{
 8         return 0;
 9     }
10   }      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                 };    

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

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

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

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

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

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

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

时间: 2024-10-09 20:34:53

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

javaScript函数与闭包

js中函数也是对象,具有一切对象的特征,可以作为表达式给变量赋值,可以作为函数的形参,或者函数的返回值,函数内可以嵌套函数等等.函数内部使用var定义的局部变量只能在函数内部进行访问,在函数调用完成后被释放,从这点,可以模拟私有变量,块状作用域等. 1.javaScript函数定义 js中函数定义有两种方法:函数声明和函数表达式,函数声明可以进行函数声明提升,函数表达式则不会. 2.闭包 闭包是指有权访问另一个函数作用域中的变量的函数,和匿名函数是不同的概念.只不过其常见的创建方式,就是在一个函

javascript函数及闭包详解

1.arguments[]对象在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们.还可以用 arguments 对象检测函数的参数个数,引用属性 arguments.length 2function对象的length属性ECMAScript 定义的属性 length 声明了函数期望的参数个数 3Function 对象也有与所有对象共享的 valueOf() 方法和 toString() 方法.这两个方法返回的都是函数的源代码,在调试时尤其有用 4闭包: 什么时

JavaScript函数及闭包

前面一片文章讲到过一点函数,了解到每声明一个函数就会产生一个作用域.而外面的作用域访问不了里面的作用域(把里面的变量和函数隐藏起来),而里面的可以访问到外面的.对于隐藏变量和函数是一个非常有用的技术. 基于作用域隐藏的方法叫做最小授权或最小暴露原则. 这个原则是指在软件设计中,应该最小限度的暴露必要内容,而将其内容都隐藏起来,比如某个模块或对象得API设计.隐藏变量和函数可以解决同名标识符的之间的冲突,冲突会导致变量的意外覆盖. 例如: var a = 2; function foo(){ va

javascript函数闭包(closure)

一,首先感受下javascript函数的闭包 二,闭包 1,定义:闭包就是能够读取其他函数内部变量的函数,由于在javascript语言中,只有在函数内部的子函数才能够读取局部变量,因此可以把闭包简单的理解成:定义在一个函数内部的函数,简而言之,闭包起到了将函数内部与函数外部连接起来的桥梁作用 2,作用:1,可以读取函数内部的变量:2,可以让这些变量的值始终保存在内存中 3,注意点:1,首先因为闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以我们不能滥用闭包,否则会对网页性能造成影响.

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

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

JavaScript函数,作用域以及闭包

JavaScript函数,作用域以及闭包 1. 函数 (1). 函数定义:函数使用function关键字定义,它可以用在函数定义表达式或者函数声明定义. a. 函数的两种定义方式: * function functionName() {} * var functionName = function(){} b. 两种函数定义不同之处 1). 声明提前问题 函数声明语句   :声明与函数体一起提前 函数定义表达式 :声明提前,但是函数体不会提前 请看下面图示:绿色线上面实在js初始加载的时候,查看

[连载]JavaScript讲义(04)--- 函数和闭包

点击下载该例子的源代码 [连载]JavaScript讲义(04)--- 函数和闭包,布布扣,bubuko.com

前端学习 第六弹: javascript中的函数与闭包

前端学习 第六弹:  javascript中的函数与闭包 当function里嵌套function时,内部的function可以访问外部function里的变量 function foo(x) {    var tmp = 3;    function bar(y) {        alert(x + y + (++tmp));    }    bar(10);}foo(2) 这时无论怎么运行输出的都是16,但这不是闭包 如果我们返回内部函数,内部function会close-over外部fu

JavaScript中的匿名函数及函数的闭包以及作用域

1. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85