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

    闭包是指有权访问另一个函数作用域的变量的函数。

    闭包的局部变量可以在函数执行结束后仍然被函数外的代码访问。这意味着函数必须返回一个指向闭包的“引用”,或将这个”引用”赋值给某个外部变量,才能保证闭包中局部变量被外部代码访问。

    在ECMAScript中,函数对象中定义的 内部函数(inner function) 是可以直接访问外部函数的局部变量,创建闭包的常见方式,就是在一个函数内部创建另一个函数。

    function welcome (name) {
         var text = 'Hello ' + name;   // local variable
         // 每次调用时,产生闭包,并返回内部函数对象给调用者
         return function () {
             console.log(text);
         }
    }
    var sayHello = welcome( "Viewer" );
    sayHello()   // 通过闭包访问到了局部变量text

    代码的执行结果是:Hello Viewer,因为 sayHello() 函数在 welcome() 函数执行完毕后,仍然可以访问到定义在其内部的局部变量 text ,这就是闭包的效果。

    在ECMAscript的脚本的函数运行时,每个函数关联都有一个执行上下文场景(Execution Context) ,这个执行上下文场景中包含三个部分:

    • 文法环境(The LexicalEnvironment)
      • 环境记录(Enviroment Recode)
      • 外部引用(指针)
    • 变量环境(The VariableEnvironment)
      • 局部变量
      • 参数变量
    • this绑定

    外部引用指向了外部函数对象的上下文执行场景。全局的上下文场景中此引用值为 NULL。这样的数据结构就构成了一个单向的链表,每个引用都指向外层的上下文场景。

    例如上面我们例子的闭包模型应该是这样,sayHello 函数在最下层,上层是函数 welcome,最外层是全局场景。如下图:

    因此当sayHello被调用的时候,sayHello会通过上下文场景找到局部变量text的值,因此在屏幕的对话框中显示出”Hello Viewer”。

    变量环境(The VariableEnvironment)和文法环境的作用基本相似。

    闭包实例

    前面的内容大致说明了Javascript闭包是什么,闭包在Javascript如何实现,下面通过针对一些例子来深入了解闭包。

    例子1:闭包中局部变量是引用而非复制

    function say667() {
        var num = 666;
        var sayAlert = function() {
            console.log(num);
        }
        num++;
        return sayAlert;
    }
      
    var sayAlert = say667();
    sayAlert()    //667

    例子2:多个函数绑定同一个闭包,因为他们定义在同一个函数内。

    function setupSomeGlobals () {
        var num = 666;
    
        // 存储一些函数的引用作为全局变量
        gAlertNumber = function() {
            console.log(num);
        }
    
        gIncreaseNumber = function() {
            num++;
        }
    
        gSetNumber = function(x) {
            num = x;
        }
    }
    
    setupSomeGlobals();     // 为三个全局变量赋值
    gAlertNumber();         //666
    
    gIncreaseNumber();
    gAlertNumber();         // 667
    
    gSetNumber(12);         
    gAlertNumber();         //12

    例子3:当在一个循环中赋值函数时,这些函数将绑定同样的闭包

    <script type="text/javascript">
      window.onload = function(){
        var lists = document.getElementsByTagName("li");
        for(var i=0,l=lists.length; i < l; i++){
          lists[i].onclick = function(){
            var t = i;
            return function(){
              console.log(t+1)
            }
          }()
        }
      }
    </script>
    
    <body>
    <h1>当在一个循环中赋值函数时,这些函数将绑定同样的闭包</h1>
    <ul>
      <li id="a1">aa</li>
      <li id="a2">aa</li>
      <li id="a3">aa</li>
    </ul>
    <body>

    例子4:外部函数所有局部变量都在闭包内,即使这个变量声明在内部函数定义之后。

    function sayAlice() {
        var sayAlert = function() {
            console.log(alice);
        }
    
        var alice = 'Hello Alice';
        return sayAlert;
    }
    var helloAlice = sayAlice();
    helloAlice();

    例子5:每次函数调用的时候创建一个新的闭包。

    function newClosure(someNum, someRef) {
        var num = someNum;
        var anArray = [1,2,3];
        var ref = someRef;
        return function(x) {
            num += x;
            anArray.push(num);
            console.log('num: ' + num +
            '\nanArray ' + anArray.toString() +
            '\nref.someVar ' + ref.someVar);
        }
    }
    closure1 = newClosure(40,{someVar:'closure 1'});
    closure2 = newClosure(1000,{someVar:'closure 2'});
      
    closure1(5); // num:45 anArray[1,2,3,45] ref:'someVar closure1'
    closure2(-10);// num:990 anArray[1,2,3,990] ref:'someVar closure2'

    由于闭包会携带包含它的函数的作用域,因此会比其它函数占用更多的内存,过度使用闭包会导致占用内存,所以只有在必要的时候再使用闭包。

    参考资料:http://yuiblog.com/blog/2006/11/27/video-crockford-advjs/

                  http://coolshell.cn/articles/6731.html

  • 相关阅读:
    Oracle基础知识整理
    linux下yum安装redis以及使用
    mybatis 学习四 源码分析 mybatis如何执行的一条sql
    mybatis 学习三 mapper xml 配置信息
    mybatis 学习二 conf xml 配置信息
    mybatis 学习一 总体概述
    oracle sql 语句 示例
    jdbc 新认识
    eclipse tomcat 无法加载导入的web项目,There are no resources that can be added or removed from the server. .
    一些常用算法(持续更新)
  • 原文地址:https://www.cnblogs.com/zhoufulin/p/4973129.html
Copyright © 2011-2022 走看看