博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript 闭包
阅读量:4334 次
发布时间:2019-06-07

本文共 4758 字,大约阅读时间需要 15 分钟。

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

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

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

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()赋给全局变量temp28 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]());

转载于:https://www.cnblogs.com/fanshaokun/p/7218432.html

你可能感兴趣的文章
分解质因数
查看>>
selective_switch.py
查看>>
Alpha通道
查看>>
[HNOI2002]彩票
查看>>
[HNOI2009]无归岛
查看>>
[SDOI2008]Sandy的卡片
查看>>
html元素li移动动态效果
查看>>
程序员的情书!
查看>>
【题解】 bzoj2748 [HAOI2012]音量调节 (动态规划)
查看>>
get改造成post请求
查看>>
BZOJ1718: [Usaco2006 Jan] Redundant Paths 分离的路径
查看>>
1284 2 3 5 7的倍数 分类: 51nod ...
查看>>
关于target=标签
查看>>
设计模式(二)工厂模式
查看>>
HDU 1426 Sudoku Killer【DFS 数独】
查看>>
二分图-匈牙利算法模板
查看>>
Linux下修改mysql root密码
查看>>
zoj 3329 概率dp
查看>>
Tomcat工作原理
查看>>
spring IOC篇二:xml的核心逻辑处理(doLoadBeanDefinitions(inputSource, encodedResource.getResource()))...
查看>>