zoukankan      html  css  js  c++  java
  • 关于闭包的所有理解

    闭包这家伙,从刚开始接触到javascript基础就走进我的脑子里,但是总感觉自己理解的不透彻,不清晰。然而,几乎每个面试官呢,又好像都挺喜欢问这个问题的,所有,没办法罗,只有再深入去探讨一下咯,哈哈。

    1.什么是闭包

    这里先给闭包下一个定义,简单概括为两点:

    1).函数嵌套函数;

    2).内层函数可以访问外层函数的变量和参数。

    2.js中的垃圾回收机制

    看代码说话:

     1         function aa() {
     2             a = 10;
     3         }
     4         aa();
     5         console.log(a); // 10  a没有var申明,默认是一个全局变量
     6         //上面代码等价于:
     7         var a;
     8         function aa(){
     9             a = 10;
    10         }
    11 
    12 
    13         // 对比下面这个例子:
    14         function aa() {
    15             var a = 10;
    16         }
    17         aa();
    18         console.log(a);  //js中的垃圾回收机制  a is not defined

    3.闭包的两个最大的用处

    1).可以读取函数内部的变量

    2).让这些变量的值始终保持在内存中(不会被垃圾回收机制所回收)

    出于种种原因,我们有时候需要得到函数内的局部变量。但是,正常情况下,这是办不到的(js的垃圾回收机制),只有通过变通方法才能实现。

    那就是在函数的内部,再定义一个函数。

     1         //example1:
     2         function f1() {
     3             var n = 999;
     4             nAdd = function () {
     5                 n += 1
     6             }; //全局变量
     7             function f2() {
     8                 alert(n);
     9             }
    10 
    11             return f2;
    12         }
    13          var result = f1();
    14          result(); // 999
    15          nAdd();
    16          result(); // 1000
    17         //这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,
    18         // 首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。
    19 
    20         //example2:
    21         (function (x) {
    22             return (function (y) {
    23                 console.log(x);
    24             })(2)
    25         })(1);
    26         // result: 1  输出1,闭包能够访问外部作用域的变量或参数。

    4.闭包只能取得包含函数中任何变量的最后一个值

    看看下面这个闭包函数:

     1         function test1() {
     2             var result = [];
     3             for (var i = 0; i < 10; i++) {
     4                 result[i] = function () {
     5                     alert(i);
     6                 };
     7             }
     8             return result;
     9         }
    10 
    11         test1()[1](); // 10

    执行任何一个test1()[i](); 结果都会弹出10.

    5.我们可以通过创建另一个匿名函数强制让闭包的行为符合预期

     1     function test2() {
     2             var result = [];
     3             for (var i = 0; i < 10; i++) {
     4                 result[i] = function (num) {
     5                     return function () {
     6                         alert(num);
     7                     }
     8                 }(i);
     9                 //也可以这样写
    10                 /*(function(m){
    11                  result[m] = function(){
    12                  alert(m);
    13                  };
    14                  })(i);*/
    15             }
    16             return result;
    17         }
    18         for (var i = 0; i < test2().length; i++) {
    19             test2()[i](); // 0,1,2,3,...,8,9
    20         }

    这里用到了立即执行函数表达式。将 JavaScript 代码包含在一个函数块中有神马意思呢?为什么要这么做?句话说,为什么要用立即执行函数表达式(Immediately-Invoked Function Expression)。IIFE 有两个比较经典的使用场景,一是类似于在循环中定时输出数据项,二是类似于 JQuery/Node 的插件和模块开发。

     1         for (var i = 0; i < 5; i++) {
     2             setTimeout(function () {
     3                 console.log(i);
     4             }, 1000);
     5         }
     6         /*上面的输出并不是你以为的0,1,2,3,4,而输出的全部是5,这时 IIFE 就能有用了:*/
     7         for (var i = 0; i < 5; i++) {
     8             (function (m) {
     9                 setTimeout(function () {
    10                     console.log(m);
    11                 }, 1000);
    12             })(i);
    13         }
    14         /* 输出 0,1,2,3,4 */
    15         
    16         /*而在 JQuery/Node 的插件和模块开发中,为避免变量污染,也是一个大大的 IIFE:*/
    17         (function($){
    18          //代码
    19          })(jQuery);

    6.闭包中关于this对象

     1         //example1:
     2         var name = "The Window";
     3         var object = {
     4             name: "My Object",
     5             getNameFunc: function () {
     6                 return function () {
     7                     return this.name;
     8                 };
     9             }
    10         };
    11         console.log(object.getNameFunc()()); // The Window 【匿名函数的执行环境具有全局性,this指向window】
    12 
    13         //example2: 改进
    14         var name = "The Window";
    15         var object = {
    16             name: "My Object",
    17             getNameFunc: function () {
    18                 var that = this;
    19                 return function () {
    20                     return that.name;
    21                 };
    22             }
    23         };
    24         console.log(object.getNameFunc()()); // My Object
    25 
    26         //example3: 
    27         var myObject = {
    28             foo: "bar",
    29             func: function () {
    30                 var self = this;
    31                 console.log("outer func:  this.foo = " + this.foo);
    32                 console.log("outer func:  self.foo = " + self.foo);
    33                 (function () {
    34                     console.log("inner func:  this.foo = " + this.foo);
    35                     console.log("inner func:  self.foo = " + self.foo);
    36                 }());
    37 
    38                //用闭包来解决
    39                 /*(function (test) {
    40                     console.log("inner func:  this.foo = " + test.foo);  //'bar'
    41                     console.log("inner func:  self.foo = " + self.foo);
    42                 })(self);*/
    43             }
    44         };
    45         myObject.func();
    46         /*
    47          * 输出结果:
    48          outer func:  this.foo = bar
    49          outer func:  self.foo = bar
    50          inner func:  this.foo = undefined
    51          inner func:  self.foo = bar
    52          * */
  • 相关阅读:
    Docker Secrets
    Docker swarm 使用服务编排部署lnmp
    Docker Swarm 服务编排之命令
    Docker Swarm应用--lnmp部署WordPress
    How to suppress 'Maybe this is program method' warnings from ProGuard
    ProGuard代码混淆详细攻略
    ProGuard代码混淆技术详解
    Web攻防之XSS,CSRF,SQL注入
    Spring中初始化bean和销毁bean的时候执行某个方法的详解
    数据库事务隔离级别+Spring 声明性事务隔离级别
  • 原文地址:https://www.cnblogs.com/xiayu25/p/6307106.html
Copyright © 2011-2022 走看看