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

    ————————————————————————————————————————————

    JavaScript闭包

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    作用域链:只有内层函数可以调用外层变量,形成一条单向的作用域链

    词法作用域:不同的函数之间不共享词法作用域,可以通过闭包来实现共享

    作用域链与词法作用域样例

     1 // 作用域链
     2 var a = 1;
     3 
     4 function test() {
     5     var b = 2;
     6 
     7     function test1() {
     8         // 在test1()中可以调用外层的变量a和b
     9         // 但是在外层无法调用内层的变量,形成了一条作用域链
    10         var c = 3;
    11         console.log(a);
    12         console.log(b);
    13         return b;
    14     }
    15     test1();
    16 }
    17 test();
    18 
    19 // 词法作用域
    20 // 不同的函数之间不共享词法作用域,可以通过闭包来实现共享
    21 // 在这种写法中,错误信息提示d未定义
    22 // function f1() {
    23 //     var d = 333;
    24 //     return f2();
    25 // }
    26 
    27 // function f2() {
    28 //     return d;
    29 // }
    30 // console.log(f1());

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    闭包

    • 在正常情况下,只有function2可以访问function1中的变量var a var b
    • 如果想要在全局作用域中访问内层变量,就需要用到"闭包"
    • 即借function2来调用function1中的变量

    优点:

    • 可以突破全局作用域链,调用函数内部变量
    • 退出后函数不会被销毁,而是保留在内存中
    • 作为迭代器来使用

    缺点:

    • 闭包会使函数中的变量都保存在内存中,内存消耗很大,不能滥用闭包。在IE中可能导致内存泄漏。在退出函数之前,尽量将不使用的局部变量全部删除
    • 闭包会在父函数外部,改变父函数内部变量的值。所以如果把父函数作为对象Object使用,把闭包当作公用方法Public Method,把内部变量作为它的私有属性Private Value,此时注意不要随便改变父函数内部变量的值

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    实现形式:

    • Demo1:通过返回函数的函数形式来返回f1中的变量

    • Demo2:利用全局变量进入到函数内部来调用

    闭包的基础形式

     1 // 通过闭包突破全局作用域链
     2 
     3 // Demo1:使用返回函数的函数来实现闭包
     4 function f1() {
     5     var a = 'aaa';
     6     return function() {
     7         return a;
     8     }
     9 }
    10 var a1 = f1();
    11 // f1()返回的是function(){return a;}
    12 console.log(typeof a1);
    13 // 要打印a的值则要用a1()
    14 console.log(a1());
    15 // 或使用二次调用
    16 var a2 = f1()();
    17 console.log(a2);
    18 
    19 // Demo2:利用全局变量进入到函数内部来调用
    20 var temp;
    21 function f3(){
    22     var b = 'bbb';
    23     temp = function(){
    24         return b;
    25     }
    26 }
    27 // 先调用f3(),将function()赋给全局变量temp
    28 f3();
    29 // 执行temp()得到变量b的内容
    30 console.log(temp());

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    闭包的应用:基本形式/迭代器

      1 // 闭包的应用
      2 // Demo1:基本应用
      3 function f1() {
      4     var n = 1;
      5     // test是全局变量
      6     test = function() {
      7         n++;
      8     }
      9 
     10     function f2() {
     11         console.log(n);
     12         return 'f2 return';
     13     }
     14     // 调用f1时返回f2()的指针
     15     return f2;
     16 }
     17 // res调用f1()时,返回f2给res
     18 var res = f1();
     19 // 打印res可以看到f2()的内容
     20 console.log(res);
     21 // 执行f2的内容可以得到n与f2()的返回值
     22 console.log(res());
     23 // 执行test()函数后n++
     24 test();
     25 // 此时调用n的值即为2
     26 console.log(res());
     27 // 说明变量n始终保存在内存中,并不会因为f1()执行结束而销毁
     28 // f1是f2()的复函数,f2又被赋予给全局变量res,f2又依赖f1,所以f1未被销毁
     29 
     30 // *******************************************************************
     31 // Demo2:设置变量访问控制,在外部不会被访问到
     32 // 全局作用域中变量getValue和setValue用于调用
     33 var setValue, getValue;
     34 // 设置自调用函数,建立初始值
     35 (function() {
     36     var num = 0;
     37     getValue = function() {
     38         return num;
     39     };
     40     setValue = function(x) {
     41         num = x;
     42     };
     43 })();
     44 // 默认得到初始值0
     45 var getNum = getValue();
     46 console.log(getNum);
     47 // 给num赋值
     48 setValue(10);
     49 // 获取获取到的值
     50 var getNum = getValue();
     51 console.log(getNum);
     52 
     53 // *******************************************************************
     54 // Demo3:迭代器效果
     55 // 对数组操作,每次调用则返回下一个元素
     56 var arr1 = ['a', 'b', 'c', 'd', 'e'];
     57 
     58 function iterator(arr) {
     59     var i = 0;
     60     return function() {
     61         return arr[i++];
     62     };
     63 }
     64 var next = iterator(arr1);
     65 console.log(next());
     66 console.log(next());
     67 console.log(next());
     68 console.log(next());
     69 console.log(next());
     70 
     71 // *******************************************************************
     72 // 迭代器的第二种形式
     73 function iterator2() {
     74     var arr2 = [];
     75     var i;
     76     // 每次循环时自调用function(x),返回function(){return x};
     77     for (i = 0; i < 3; i++) {
     78         arr2[i] = (function(x) {
     79             return function() {
     80                 return x;
     81             };
     82         })(i);
     83     }
     84     return arr2;
     85 }
     86 // 在这里next2是一个数组,数组的内容是function(){return x;};
     87 var next2 = iterator2();
     88 console.log(next2);
     89 // next2[0]执行return x;
     90 console.log(next2[0]());
     91 console.log(next2[1]());
     92 console.log(next2[2]());
     93 
     94 // *******************************************************************
     95 // 迭代器的第三种形式
     96 function iterator3() {
     97     // 闭包函数
     98     function test3(x) {
     99         return function() {
    100             return x * 10;
    101         }
    102     }
    103     var arr3 = [];
    104     var i;
    105     for (i = 0; i < 3; i++) {
    106         // 每次循环时调用闭包函数赋给a[i];
    107         arr3[i] = test3(i);
    108     }
    109     return arr3;
    110 }
    111 var next3 = iterator3();
    112 console.log(next3);
    113 console.log(next3[0]());
    114 console.log(next3[1]());
    115 console.log(next3[2]());

     

  • 相关阅读:
    Ubuntu 15.04 开机无法进入图形界面,自动进入emergency mode解决方法
    Docker常用命令
    安装mongodb时报错 configure: error: Cannot find OpenSSL's libraries
    Invalid command 'Header', perhaps misspelled or defined by a module not included in the server configuration
    mysql varchar类型转换int类型
    elasticsearch 安装 head插件
    解决linux下root运行Elasticsearch异常
    PHP 数组中出现中文乱码,json_encode返回结果为null 或false
    Git命令_git remote与远程仓库管理
    Git命令_git clone和git fork的区别以及pull request含义
  • 原文地址:https://www.cnblogs.com/hughdong/p/7210860.html
Copyright © 2011-2022 走看看