zoukankan      html  css  js  c++  java
  • js闭包

      在程序设计语言中,闭包(即词法闭包lexical closures或函数闭包function closures)是用一等函数(first class)实现词法作用域(lexically scoped)名称绑定(name binding)的一种技术。操作上说,一个闭包是一个用来存储一个函数及其环境的一条记录(record),这个环境会在闭包创建的时候,在函数的每个自由变量(free variable——在局部使用,但是定义在外部作用域)与其值或名称绑定的存储区之间建立一个映射。不同于一般普通函数(plain function),即使当函数在其作用域外被调用时,闭包仍然允许函数通过闭包的引用访问(存取)捕获的变量(captured variables)。

      以上释义比较抽象,我们先用JavaScript语言举一个简单的例子并加以说明(我在此采用维基百科中说给出的例子并加以改写),在段代码与以上概念之间建立一个映射,让大家有一个直观的概念。稍后,我们再来理解这些概念是什么、如何理解?

    function   startAt(CAPTURED) {
    
      function incrementBy(i) {
    
          return CAPTURED + i;
    
      }
    
      return incrementBy;
    
    }
    

      以上的代码片段定义了一个高阶函数(higher-order function)startAt,这个函数接收一个参数CAPTURED(我将由闭包捕获的变量大写。这并不是JavaScript的标准实践,也不鼓励这样做,这里只是为了方便说明[4])和一个内部函数(nested function) incrementBy。尽管CAPTURE变量不是incrementBy的局部变量,由于incrementBy处于CAPTURED变量的词法作用域中,这个内部函数可以访问变量CAPTURED。函数startAt返回了一个包含函数incrementBy的闭包,这个函数把变量i与CAPTURED相加然后和CAPTURED在当前(this)调用startAt的一个引用返回,所以当incrementBy被调用时会知道当前的CAPTURED的值。

    应用以上函数得到运行结果如下:

    var   startAt10 = startAt(10); // closure1
    
    var   startAt100 = startAt(100); // closure2
    
    startAt10(1);
    
    >>   11
    
    startAt100(1);
    
    >>   101
    

      我们注意到,因为startAt返回一个函数,所以变量startAt10 和 startAt100 是属于函数类型。运行startAt10(1)会返回11,运行startAt100(1)会返回101。尽管startAt10和startAt100都关联到同一个函数incrementBy,相关的环境却不同,调用闭包会将CAPTURED与不同值的不同变量绑定,因此执行函数会得到不同的结果。

    --------------------------------- 使用闭包 ---------------------------------

    JavaScript经常使用下面这种模式,把捕获的亦是作为私有数据:

    var pingpong = (function() {
    	var PRIVATE = 0;
    
    	return {
    		inc: function( n ) {
    			return PRIVATE += n;
    		},
    		dec: function( n ) {
    			return PRIVATE -= n;
    		}
    	}
    })();
    
    pingpong.inc( 100 );
    //=> 100;
    
    pingpong.dec( 7 );
    //=> 93

      对象pingpong是由作为块作用域的匿名函数构建,并包含两个闭包 inc 和 dec 。最有趣的部分是,捕获的变量 PRIVATE 是这两个闭包的私有变量,除了通过调用这两个函数之一,无法通过任何手段进行访问:

    pingpong.inc( 100 );
    //=> 100;

    pingpong.dec( 7 );
    //=> 93

      甚至添加其他函数也是安全的:

    pingpong.div = function( n ) {return PRIVATE / n;};

    pingpong.div( 3 );

    //ReferenceError: PRIVATE is not defined

    --------------------------------- 闭包的抽象 ---------------------------------

    闭包为JavaScript提供了私有访问,这是一种提供抽象的好方法(例如闭包允许你在创建函数时做一些“配置”)。创建一个名为“plucker”的函数,接收一个键并将其传给一个关联结构,如数组或对象,返回键值的函数。具体实现如下:

    function plucker( FIELD ) {
      return function( obj ) {
        return ( obj && obj[FIELD] );
      }
    }
    

      

    通过测试这个实现可以看出其行为:
    var best = {title: "Infinite Jest", author: "BY"};
    var getTitle = plucker( "title" );
    getTitle( best );
    //=> Infinite Jest

    正如我所提到的,plucker 也可以操作数组:
    var books = [{title: "BY"}, {stars: 5}, {title: "X"}];
    var third = plucker( 2 );
    third( books );
    //=> {title: "X"}

  • 相关阅读:
    分享PHP获取客户端IP的几种不同方式
    php魔术方法get和set举例
    PHP正确匹配图片路径
    PHP通用的防注入过滤用户字符串函数
    用PHP逐行读取TXT文件
    atitit.ajax 最佳实践跟框架选型 o99
    Atitit.研发管理提升效率软件开发方法DSM总结o99
    Atitit. js mvc 总结(2)angular 跟 Knockout o99 最佳实践
    atitit.hbnt orm db 新新增更新最佳实践o99
    Atitit.提升稳定性分析内存泄漏PermGen OOM跟解决之道...java
  • 原文地址:https://www.cnblogs.com/frontendBY/p/4770756.html
Copyright © 2011-2022 走看看