zoukankan      html  css  js  c++  java
  • 一道闭包经典题目

    function fun(n,o) {
      console.log(o)
      return {
        fun:function(m){
          return fun(m,n);
        }
      };
    }
    var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);//undefined,?,?,?
    var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,?
    var c = fun(0).fun(1);  c.fun(2);  c.fun(3);//undefined,?,?,?
    //问:三行a,b,c的输出分别是什么?

    我理解的闭包:

      闭包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。它的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

      上面的题目就相当于内部return的fun读取全局声明的fun作用域内的变量。

    我们需要了解的知识点:

    1、JS中有几种函数类型

      具名函数(命名函数)

      匿名函数

    2、创建函数的几种方式

      ① 声明函数

        最普通最标准的声明函数方法,包括函数名及函数体    

    function fn1(){}

      ② 创建匿名函数表达式

        创建一个变量,变量的内容为一个函数。此种方式创建的函数为匿名函数。

    var fn1=function (){}

      ③ 创建具名函数表达式

        创建一个变量,变量的内容为一个具名函数。此种方式创建的函数,只能在创建的函数内部使用test调用,在函数外部只能使用fn1来调用此函数。

    var fn1=function test(){};

      ④ Function构造函数

        可以给Function构造函数传入一个函数字符串,返回包含这个函数字符串的匿名函数。  

        

       ⑤ 自执行函数

        

     3、三个fun函数的关系如何?

      分析这道题,题目中出现了三个fun,首先搞清楚三个fun之间的关系。

      第一个fun函数,是标准具名函数声明,是新创建的函数,它的返回值是一个对象字面表达式,属于一个新的object。

    function fun(n,o) {
      console.log(o)
      return {
        fun:function(m){
          //...
        }
      };
    }

      所有匿名生成的函数都是一个新函数。所以第一个fun和第二个fun不相同,均为新创建的函数。

    4、函数作用域链

      声明函数时各函数都有各自的作用域,相互关联的函数形成一条作用域链,函数在执行时,从上到下(从里到外)查找使用到的变量。

      在说第三个fun之前需要说下函数作用域链,在函数表达式内部能不能访问存放当前函数的变量。

      ① 访问对象对象内部的函数表达式

      

      ②  访问非对象内部的函数表达式

      

       采用var的是在外部创建了一个fn变量,函数内部当然可以在内部寻找不到fn后向上册作用域查找fn,而在创建对象内部时,因为没有在函数作用域内创建fn,所以无法访问。

      所以最内层return出去的函数,是第一个在全局var声明的fun。

     

    5、题目分析

    function fun(n,o) {
      console.log(o)
      return {
        fun:function(m){
          return fun(m,n);
        }
      };
    }
    var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);//undefined,?,?,?
    var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,?
    var c = fun(0).fun(1);  c.fun(2);  c.fun(3);//undefined,?,?,?
    //问:三行a,b,c的输出分别是什么?

      第一行a是在调用第一个fun, 后三个a.fun均是在调用第二个fun。

        第一次调用fun时,传入fun(0),n = 0, o = undefined。

        第二次调用a.fun(1)时,调用的是return出的函数, m = 1 ,此时闭包取到上层函数的n值,n = 0。所以a.fun(1) 输出 0 。

        第三次调用a.fun(2)时,相当于重新调用第一个fun内部return出的fun函数,m = 2,闭包取到上层函数的n,n = 0。a.fun(2)依旧是 0。

        第四次同上,a.fun(3) 输出 0。

        结果为 undefined, 0, 0, 0

      第二行b是一条链式调用,第一个fun(0)调用的是第一个fun函数,fun(0).fun(1)调用的是第二个fun函数(根据函数作用域链,先从自身找fun,没有的话再向上查找),fun(0).fun(1).fun(2),fun(0).fun(1).fun(2).fun(3)调用都是第二个fun函数。

        fun(0)传入n = 0 , o = undefined。

        fun(0).fun(1),n = 0 , m = 1 此时调用到外层时,n = 1, o = 0,输出 o 的值 为0。

        fun(0).fun(1).fun(2),因为闭包在第一个函数内,所以可以接着取到上次的n值为1,再次调用第二个fun时,m = 2, n = 1。相当于第一个fun的 n = 2, o = 1,所以输出 1 。  

        fun(0).fun(1).fun(2).fun(3),同第三步, m = 3, n = 2,相当于 n = 3, o = 2。输出 o的值 2。

        结果为undefined, 0, 1, 2 

      理解了第二行的调用,第三行c的调用就很容易了

        fun(0).fun(1),调用第一个fun传入n = 0, o = undefiend,再调用内部return的fun传入1,0, 输出 o值 0 。

        c.fun(2), 调用第二个fun函数,传入2,1,输出 1。

        c.fun(3), 同上,输出 1。

        结果为 undefined, 0, 1, 1

  • 相关阅读:
    ios初学者之Tableview的增删移
    ios初学者之在真机上调试应用程序
    androud 自定义属性
    在使用androidStudio中所遇到的错误
    用ticons指令结合ImageMagickDisplay工具批量生成Android适应图片
    android 处理302地址
    Android获取屏幕长宽
    自定义的屏幕适配方法
    android小技巧和注意事项
    redis哨兵&codis
  • 原文地址:https://www.cnblogs.com/gwf93/p/15233545.html
Copyright © 2011-2022 走看看