zoukankan      html  css  js  c++  java
  • js匿名函数和闭包总结

    js匿名函数和闭包总结

    一、总结

    一句话总结:匿名函数的最主要作用是创建闭包,闭包就是将函数内部和函数外部连接起来的一座桥梁。内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕。闭包可以用来模仿块级作用域等等。

    匿名函数 闭包:匿名函数的最主要作用是创建闭包,闭包就是将函数内部和函数外部连接起来的一座桥梁。内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕。闭包可以用来模仿块级作用域等等

    1、js匿名函数基本格式?

    匿名函数 赋值 变量
    立即执行 匿名函数 ()()
    return 匿名函数

    没有名字 可以赋值

      //情况1.把匿名函数赋值给变量
      var fn=function (){
        alert('我是匿名函数')
      }
      alert(fn)   //会将函数表达式输出
      fn()
     
    
        //情况2.匿名函数通过表达式自我执行
     (function (){
        alert('我是匿名函数')
      }
     )()
        var name='The Window';
        var obj={
          name:'my obj',
          get:function(){
              return function(){
                return this.name;
              }
            }
          }
    
          alert(obj.get()()) //这次返回的是全局变量 'The Window'
          alert(obj.get().call(obj))//这次又返回的是'my obj',因为call()强制改变了this的指向

    2、js 中的匿名函数如何自己运行?

    (匿名函数)()

    因为js中的()可以将函数代码段运行,也可以将变量转化为函数

      (function(m,n){
        alert(m+n)
      })(1000,1000)

    匿名函数

    没有函数名字的函数

    1. 单独的匿名函数是无法运行和调用的
    2. 可以把匿名函数赋值给变量
    3. 通过表达式自我执行,语法:(匿名函数)()
    4. 匿名函数传递参数,语法:(匿名函数)(参数)

    3、js中的匿名函数如何传递参数?

    ()() 括号 传参

    匿名就是()()的格式

     //匿名函数传递参数
     function myfn(m,n){
        alert(m+n)
      }
      myfn(100,100);
    
      (function(m,n){
        alert(m+n)
      })(1000,1000)

    4、js变量后的()可以表示哪些意思?

    变量 变成 方法
    执行 匿名函数

    a、将变量变成方法

    b、放在匿名函数后面,用来执行匿名函数,这样做的话匿名函数本身也要用括号扩起来,

    5、js中的闭包是什么?

    函数 嵌套 匿名函数

    在一个函数中嵌套了一个匿名函数,匿名函数可以访问这个函数里面的变量

     闭包的相关概念

      • 闭包的英文单词是closure,是指有权访问另一个函数作用域中变量的函数。
      • 在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕
      • 这是JavaScript中非常重要的一部分知识,因为使用闭包可以大大减少我们的代码量,使我们的代码看上去更加清晰等等,总之功能十分强大。

    注:这些概念了解即可,接下来我们将通过实例来进行了解。

    6、匿名函数最大的作用是什么?

    创建闭包

     闭包的相关概念

      • 闭包的英文单词是closure,是指有权访问另一个函数作用域中变量的函数。
      • 在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕。
      • 这是JavaScript中非常重要的一部分知识,因为使用闭包可以大大减少我们的代码量,使我们的代码看上去更加清晰等等,总之功能十分强大。

    注:这些概念了解即可,接下来我们将通过实例来进行了解。

    7、alert(myfn);alert(myfn());alert(myfn()())得到的结果分别是什么?

    整个函数表达式 匿名函数表达式 执行结果
        function myfn(){
    
          return function (){
    
            return('**********')
    
          }
        }
    
        //alert(myfn)  //输出整个函数表达式
        //alert(myfn())  //输出匿名函数表达式
    
         //调用方式1
        alert(myfn()()) 

    8、闭包的用途是什么?

    局部变量 常驻内存

    闭包的相关知识点

    1. 常见的方式是在函数内部创建另一个函数
    2. 闭包的第一个用途:通过闭包可以访问局部变量
    3. 闭包的第二个用途:可以让局部变量的值始终保持在内存中
      • 优点:可以把局部变量驻留在内存中,可以避免使用全局变量;

        全局变量在复杂程序中会造成许多麻烦(比如命名冲突,垃圾回收等),所以推荐使用私有的,封装的局部变量。而闭包可以实现这一点。

      • 缺点:由于闭包里作用域返回的局部变量资源不会被立刻销毁回收,所以可能会占用更多的内存;所以过度使用闭包会导致性能下降;
    4. 循环函数中的匿名函数和闭包问题

    9、add()()的方式为何无法让闭包实现函数局部变量的累加?

    初始化
    // add()();add()();add()();//这种调用方式会出错,因为每次调用 num都会初始化一次;
    var fn=add() ;fn();fn();fn();//只在这里初始化一次,后边调用的时候执行的是里边的匿名函数
      function add(){
    
          var num= 100; // 这里改为局部变量;
    
           return function(){
            num++;
            alert(num);
           }
    
        };
        
       // add()();add()();add()();//这种调用方式会出错,因为每次调用 num都会初始化一次;
    
       var fn=add()//只在这里初始化一次,后边调用的时候执行的是里边的匿名函数
    
       fn();fn();fn();
    
       fn=null //应及时解除引用,否则会占用更多存

    10、如何解决闭包将局部变量注入内存的缺点?

    赋值 null
    fn=null //应及时解除引用,否则会占用更多存

     闭包的相关知识点

    1. 常见的方式是在函数内部创建另一个函数
    2. 闭包的第一个用途:通过闭包可以访问局部变量
    3. 闭包的第二个用途:可以让局部变量的值始终保持在内存中
      • 优点:可以把局部变量驻留在内存中,可以避免使用全局变量;

        全局变量在复杂程序中会造成许多麻烦(比如命名冲突,垃圾回收等),所以推荐使用私有的,封装的局部变量。而闭包可以实现这一点。

      • 缺点:由于闭包里作用域返回的局部变量资源不会被立刻销毁回收,所以可能会占用更多的内存;所以过度使用闭包会导致性能下降;
    4. 循环函数中的匿名函数和闭包问题
      function add(){
    
          var num= 100; // 这里改为局部变量;
    
           return function(){
            num++;
            alert(num);
           }
    
        };
        
       // add()();add()();add()();//这种调用方式会出错,因为每次调用 num都会初始化一次;
    
       var fn=add()//只在这里初始化一次,后边调用的时候执行的是里边的匿名函数
    
       fn();fn();fn();
    
       fn=null //应及时解除引用,否则会占用更多存

    11、js如何让循环中的匿名函数和闭包接收到的i正确?

    匿名函数 立即执行
    匿名函数 内 匿名函数 传参数

    函数内部的匿名函数立即执行

        //让匿名函数立即执行来赋值
        function fun(){
             var arr=[];
             for(var i=0; i<5; i++){
                arr[i]=(function(){ 
                    return '元素'+i;
                })()
             }
             return arr
          }
        var Bb=fun()
        alert(Bb.length)
        alert(Bb)
        // for(var i=0; i<5; i++){
    
        //   alert(Bb[i]) 
        // }

    匿名函数内部加一层匿名函数(加传参):常见结构

     1   //通过闭包让局部变量驻留在内存中
     2   function fun(){
     3          var arr=[];
     4          for(var i=0; i<5; i++){
     5             arr[i]=function(n){ 
     6                 return function(){ 
     7                   return '元素'+n;
     8                 }
     9             }(i) 
    10          }
    11          return arr
    12       }
    13     var Bb=fun()
    14     //alert(Bb.length)
    15    // alert(Bb[0]())
    16     for(var i=0; i<5; i++){
    17         //alert(Bb[i]) 
    18         alert(Bb[i]()) 
    19     }
    20     //这次成功的输出了 ‘元素0 元素1 元素2 元素3 元素4 ’,而不再都是[元素5]
    21     /*
    22       1.这里的匿名函数有一个参数 n,也就是最终将返回的结果数值;
    23       2.在调用每个匿名函数时传入变量i
    24       3.变量i的当前值会赋值给n,
    25       4.匿名函数内部创建并返回了一个访问n的闭包
    26       5.如此数组arr中的每个函数中都有了自己的n变量的一个副本(闭包可以将局部变量贮存在内存中)
    27 
    28     */

    闭包的相关知识点

    1. 常见的方式是在函数内部创建另一个函数
    2. 闭包的第一个用途:通过闭包可以访问局部变量
    3. 闭包的第二个用途:可以让局部变量的值始终保持在内存中
      • 优点:可以把局部变量驻留在内存中,可以避免使用全局变量;

        全局变量在复杂程序中会造成许多麻烦(比如命名冲突,垃圾回收等),所以推荐使用私有的,封装的局部变量。而闭包可以实现这一点。

      • 缺点:由于闭包里作用域返回的局部变量资源不会被立刻销毁回收,所以可能会占用更多的内存;所以过度使用闭包会导致性能下降;
    4. 循环函数中的匿名函数和闭包问题

    12、js匿名函数中的this指代的是谁?

    window

    闭包中的this问题

    • 之前的课程中讲过this是在运行时基于函数的执行环境来绑定的
    • 全局函数中的this是window,而当函数作为某个对象的方法调用时,this就是指的那个对象......
    • 匿名函数的执行环境具有全局性,this通常是指向window的。
      • 可以使用对象冒充强制改变this的指向
      • 将this赋值给一个变量,闭包访问这个变量
        var name='The Window';
        var obj={
          name:'my obj',
          get:function(){
              return function(){
                return this.name;
              }
            }
          }
    
          alert(obj.get()()) //这次返回的是全局变量 'The Window'

    13、如何让匿名函数中的this指向当前对象?

    对象冒充 闭包访问

    匿名函数的执行环境具有全局性,this通常是指向window的。

    • 可以使用对象冒充强制改变this的指向
    • 将this赋值给一个变量,闭包访问这个变量

    对象冒充

        var name='The Window';
        var obj={
          name:'my obj',
          get:function(){
              return function(){
                return this.name;
              }
            }
          }
    
          alert(obj.get()()) //这次返回的是全局变量 'The Window'
          alert(obj.get().call(obj))//这次又返回的是'my obj',因为call()强制改变了this的指向

    闭包访问

      var name='The Window';
        var obj={
          name:'my obj',
          get:function(){
            //这里的this指的是对象,这里为obj
            var self=this
              return function(){
                //闭包里的this指的是window
                return self.name;
              }
            }
          }
    
          alert(obj.get()()) 

    14、如何模仿块级作用域?

    立即执行 匿名函数

    用匿名函数

    将需要放进块级作用域的东西放进一个立即执行的匿名函数里面

    js没有块级作用域代码

      function myfun() {
    
        for(var i=0;i<5;i++){
    
        }  //i不会因为离开了for块就失效;
    
        var i; //重新声明后i还是5,
    
        alert(i)  //此时的i=5
      }

    模仿块级作用域

      <script>
       //模仿块级作用域
       function myfun() {
    
        (function(){
          for(var i=0;i<5;i++){
              alert(i)  
          } 
        })()  // 这里定义并立即调用了一个匿名函数; 
        
    
        alert(i) 
     //此时的i已结不存在 会报错:'i is not defined'
      }
      myfun()
      </script>

    块级作用域又叫私有作用域,但是JS没有块级作用域的概念;这意味着在块语句(比如for语句)中定义的变量,不会因为离开了for块就失效。

    • 使用了块级作用域后,匿名函数中定义的任何变量,都会在执行结束时被销毁;
    • 一般来说,我们都应该尽可能少向全局作用域中添加变量和函数;过多的全局变量和函数很容易导致命名冲突
    • 使用块级作用域,每个开发者既可以使用自己的变量,又不必担心搞乱全局作用域;
    • 在全局作用域中使用块级作用域可以减少闭包占用的内存问题.

    15、js对象如何创建私有变量和类似其它语言的get、set方法(特权方法)?

    私有变量 对象 private 权限
    特权方法 this 属性 匿名方法

    this方式定义的变量方法外部可以访问

    var方式定义的吧变量方法外部无法访问

    私有变量也就是例如java对象的private权限的变量

    var name='张三'; // 私有变量;

    特权方法其实是this的一个属性,这个属性指向一个匿名方法,因为是当前对象的属性,所以外部可以访问

    this.getname=function(){ // 对外公共的特权方法;
      return name;
    }

    私有变量

    JavaScript没用私有属性的概念;所有的属性都是公用的;

    私有变量的概念:在任何函数中定义的变量,都是私有变量,因为不能在函数外部访问这些变量;

    • 私有变量:包括函数的参数/局部变量和在函数内部定义的其他函数;
    • 特权方法:内部创建一个闭包,闭包可以访问私有变量;因此创建用于访问私有变量的公用方法,称作特权方法
    • 可以通过构造方法传参来访问私有变量

      这种方法的缺点是会为每一个实例创建一组新的方法,不能实现共享。

      function People(){
          var name='张三'; // 私有变量;
          var age='30';
          function say(){  // 私有函数;
            return '我是......';
          }
    
          this.getname=function(){ // 对外公共的特权方法;
            return name;
          }
    
          this.getsay=function(){
            return say()
          }
      }
      var p=new People()
      alert(p.getname())
      alert(p.getsay())

    16、对象创建的时候,用this声明的属性和用var定义的局部变量创建的对象是不同的?

    this 属性 访问 变量 public 权限
    var 函数变量 无法访问 变量 private 权限

    使用this方式的话是对象的属性,外部可以轻松访问变量,相对于java中给变量设置权限public

    使用var方式的话,是函数变量(局部变量,私有变量),函数外部无法访问,相对于java中非变量设置private权限,使用特权方法可以访问,特权方法相对于get/set方法,

    使用this方式

      function People(){
          this.name='张三';
          this.age='30';
          this.say=function (){
            return '我是'+this.name+'......';
          }
      }

    使用var方式

    function People(){
          var name='张三'; // 私有变量;
          var age='30';
          function say(){  // 私有函数;
            return '我是......';
          }
    
          this.getname=function(){ // 对外公共的特权方法;
            return name;
          }
    
          this.getsay=function(){
            return say()
          }
      }

    17、js对象如何创建静态变量(静态私有变量)?

    立即执行的闭包 原型 特权方法 块级作用域

    静态私有变量

    通过块级作用域(私有作用域)中定义私有变量或函数,创建对外公共的特权方法;

    • 首先创建私有作用域
    • 定义私有变量或函数
    • 定义构造函数和特权方法
    • 这种方式创建的私有变量因为使用原型而实现共享
    • 同时由于共享,实例也就没有自己的私有变量。
     1   (function(){
     2     var name='张三';
     3     User=function(){} //构造函数
     4     User.prototype.getName=function(){
     5         return name
     6       }
     7     User.prototype.setName=function(value){
     8         name=value
     9       };
    10   })()
    11 
    12   var VIP1=new User() //因为Uer()是私有函数,所以外部无法访问。
    13   //alert(VIP1.getName())
    14   VIP1.setName('李四')
    15   //alert(VIP1.getName())
    16 
    17   var VIP2=new User()
    18   alert(VIP2.getName()) 

    18、js对象为何会用到静态私有变量(静态方法)?

    共享

    共享肯定是要通过原型的

    私有变量方式的缺点是会为每一个实例创建一组新的方法,不能实现共享。

    19、下面代码是匿名函数么?

    函数 名字
    get:function(){
              return this.name;
            }
          }

    这只是json写法的对象中的函数而已,就是讲函数赋值给一个变量,这个函数是有名字的,所以不叫闭包

          get:function(){
              return function(){
                return this.name;
              }
            }

    这个才是闭包

    这个不是

          var obj={
          name:'my obj',
          get:function(){
              return this.name;
            }
          }
          alert(obj.get())  //返回 'my obj'

    这个是

        var name='The Window';
        var obj={
          name:'my obj',
          get:function(){
              return function(){
                return this.name;
              }
            }
          }
    
          alert(obj.get()()) //这次返回的是全局变量 'The Window'
          alert(obj.get().call(obj))//这次又返回的是'my obj',因为call()强制改变了this的指向

    二、内容在总结中

     
  • 相关阅读:
    Hadoop——Hive的序列化,文件存储,分桶和分区
    Hadoop——Hive的数据操作
    Hadoop——Hive简介和环境配置
    Hadoop基础——优化策略
    Hadoop基础——HDFS、MapReduce、Yarn的运行原理和机制
    JavaScript基础
    mysql 基本操作
    初学——java反射
    Java初学—多线程
    ubuntu增加工作分区(workspace)命令
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/10222982.html
Copyright © 2011-2022 走看看