微信扫一扫打赏支持

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的指向

 

 

 

 

 

二、内容在总结中

 

 

 

 
posted @ 2019-01-05 06:31  范仁义  阅读(1243)  评论(0编辑  收藏  举报