什么是闭包

  • 函数嵌套函数
  • 内部函数可以引用外部函数的参数和变量
  • 参数和变量不会被垃圾回收机制所回收

    1. <script>
    2. function aaa(b){
    3. var a = 10;
    4. console.log(a, b);
    5. function bbb(){
    6. console.log(a,b);
    7. }
    8. return bbb;
    9. }
    10. var res = aaa(20);//10 20
    11. console.log(res);//ƒ bbb(){console.log(a,b);}(res代表嵌套函数bbb)
    12. res();
    13. </script>

    垃圾回收机制

  • 垃圾回收机制是指函数内部的形参和变量随着函数的调用被创建,随着函数调用结束而被销毁。

    闭包的好处

  • 希望一个变量常驻内存当中

  • 避免全局变量污染

    1. //闭包函数的美化,函数声明以后立即调用的写法,叫做立即执行函数。
    2. var ccc = (function(){
    3. var a = 2;
    4. return function(){
    5. a++;
    6. console.log(a);
    7. }
    8. })();
    9. ccc();
    10. ccc();
  • 可以声明私有成员 ```javascript //A同学 var moduleA = (function(){

    1. var count = 0; //私有变量 只能被私有方法访问
    2. function showA(){ //私有方法
    3. count += 20;
    4. console.log(count);
    5. }
    6. function showB(){
    7. count += 10;
    8. console.log(count);
    9. }
    10. return {
    11. outA: showA,
    12. outB: showB
    13. }

    })();

    moduleA.outA(); moduleA.outB(); // console.log(count);报错 // console.log(showA);报错

  1. //B同学
  2. var moduleB = (function(){
  3. var count = 1000; //私有变量 只能被私有方法访问
  4. function showA(){ //私有方法
  5. count += 200;
  6. console.log(count);
  7. }
  8. function showB(){
  9. count -= 100;
  10. console.log(count);
  11. }
  12. return {
  13. outA: showA,
  14. outB: showB
  15. }
  16. })();
  17. moduleB.outA();
  18. moduleB.outB();
  1. <a name="3kTp5"></a>
  2. ## 给每个按钮添加点击
  3. ```javascript
  4. //闭包方法
  5. window.onload = function(){
  6. var aBtns = document.getElementsByTagName("button");
  7. //通过循环给每一个按钮添加点击
  8. for(var i = 0; i < aBtns.length; i++){
  9. aBtns[i].onclick = (function(index){
  10. return function(){
  11. alert(index);
  12. }
  13. })(i);
  14. }
  15. }
  16. <body>
  17. <button>按钮1</button>
  18. <button>按钮2</button>
  19. <button>按钮3</button>
  20. </body>
  21. //this方法
  22. window.onload = function(){
  23. var aBtns = document.getElementsByTagName("button");
  24. //通过循环给每一个按钮添加点击
  25. for(var i = 0; i < aBtns.length; i++){
  26. aBtns[i].index = this;
  27. aBtns[i].onclick = function(){
  28. console.log(this.index);
  29. }
  30. }
  31. 还有就是把var改为this

启动延时器

  1. for(let i = 0; i < 5; i++){
  2. setTimeout(function(){
  3. console.log(i);
  4. }, 4000);
  5. }
  6. for(var i = 0; i < 5; i++){
  7. setTimeout((function(index){
  8. return function(){
  9. console.log(index);
  10. }
  11. })(i), 4000);
  12. }

函数的防抖

  1. window.onload = function(){
  2. var oBtn = document.getElementById("btn1");
  3. var i = 0;
  4. function antiShake(funcName, delay){
  5. var timer = null;
  6. return function(){
  7. var argus = [...arguments];
  8. var _this = this;
  9. clearTimeout(timer);
  10. timer = setTimeout(function(){
  11. //this指向 参数
  12. funcName.apply(_this, argus)
  13. }, delay);
  14. }
  15. }
  16. function show(ev){
  17. console.log(i++, ev);
  18. }
  19. show = antiShake(show, 500);
  20. oBtn.onclick = show;
  21. }
  22. ////////////
  23. function antiShake(funcName, delay){
  24. var timer = null;
  25. return function(){
  26. // var argus = [arguments];
  27. // var _this =this;
  28. clearTimeout(timer);
  29. timer = setTimeout(() =>{
  30. funcName();
  31. },delay)
  32. }
  33. }

函数的节流

  1. window.onload = function(){
  2. var node = document.getElementById("div1");
  3. var i = 0;
  4. //函数调用频率太快了 降频率
  5. // var timer = null;
  6. // node.onmousemove = function(){
  7. // if(!timer){
  8. // timer = setInterval(function(){
  9. // node.innerHTML = i++;
  10. // clearInterval(timer);
  11. // timer = null;
  12. // }, 500);
  13. // }
  14. // }
  15. function show(){
  16. node.innerHTML = i++;
  17. }
  18. show = throttle(show, 2000);
  19. node.onmousemove = show;
  20. }
  21. function throttle(funcName, delay){
  22. var timer = null;
  23. return function(){
  24. var argus = [...arguments];
  25. var _this = this;
  26. if(!timer){
  27. timer = setInterval(function(){
  28. funcName.apply(_this, argus);
  29. clearInterval(timer);
  30. timer = null;
  31. }, delay)
  32. }
  33. }
  34. }

闭包的缺点

  • 闭包会导致内存泄漏(由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除)

    1. window.onload = function(){
    2. var node = document.getElementById('div1');
    3. var id = node.id;//不要在闭包中直接传入对象,借用上面函数的变量,缓解内存泄漏
    4. node.onclick = function(){
    5. alert(id);
    6. }
    7. node.onclick = null;//取消闭包
    8. node = null;//取消对象
    9. }
    10. //IE浏览器
    11. window.onload = function(){
    12. var node = document.getElementById("div1");
    13. node.onclick = function(){
    14. alert(node.id);
    15. }
    16. window.onunload = function(){
    17. //页面解构的时候执行
    18. node.onclick = null;
    19. node = null;
    20. }
    21. }

    观察者模式

    1. <script>
    2. function Observer(){
    3. this.users = [];
    4. }
    5. Observer.prototype.subscibe = function(user){
    6. this.users.push(user);
    7. }
    8. Observer.prototype.unsubscibe = function(user){
    9. this.users = this.users.filter(item => item != user);
    10. }
    11. //msg 广播的数据
    12. Observer.prototype.broadcast = function(msg){
    13. //遍历所有的用户,进行广播
    14. for(var i in this.users){
    15. this.users[i](msg);
    16. }
    17. }
    18. //实战:
    19. var kai55 = new Observer();
    20. function xiaoming(msg){
    21. console.log("您好,您有一条新消息:" + msg + ", 小明说:五五开绝对没有开挂");
    22. }
    23. function xiaohua(msg){
    24. console.log("您好,您有一条新消息:" + msg + ", 小花说:五五真帅");
    25. }
    26. kai55.subscibe(xiaoming);
    27. kai55.subscibe(xiaohua);
    28. kai55.broadcast("五五开要开播了,我55开,绝对没有开挂");
    29. kai55.unsubscibe(xiaoming);
    30. kai55.broadcast("道歉");
    31. </script>