网上搜到一条关于闭包的题目,利用自己薄弱的闭包知识尝试阐述

话不多说,直接贴代码,阐述都在注释中,有幸有大牛看到的话,恳请指正错误!

function fun(n,o) {
    console.log(o);
    return {
        fun:function(m) {
            return fun(m,n);
        }
    };
}
var a = fun(0);  //undefined
a.fun(1);  //0
a.fun(2);  //0
a.fun(3);  //0
console.log('------------------------------')
var b = fun(0).fun(1).fun(2).fun(3);   //undefined  0  1  2
console.log('------------------------------')
var c = fun(0).fun(1);
c.fun(2);
c.fun(3);  //undefined  0  1  1

/** 思路前瞻: !!!一定要理解好return返回的是什么!!!
 *
 * var a = fun(0)
 * 这个比较好理解,单纯就是没有给o赋值,因此是undefined
 * 后面返回给a的是这样一个对象
 *
 * {
        fun:function(m) {
            return fun(m,n);
        }
    }
 *
 * 其中,n就是0,因为当对象属性内的n不能在当前词法作用域找到,编译器就会按照作用域链
 * 往父级作用域查找,找到了其中的n=0
 * 因此可以吧a的值写作
 * {
        fun:function(m) {
            return fun(m,0);
        }
    }
 * 实际上也应该是这个,且这个由于闭包作用,它所引用的n是不会被释放的,
 * 所以它一直不会被重置,这就解释了后面的输出为什么是0
 * ---------------------------------------------------------------------------- *
 *
 * a.fun(1)
 * 第一步。在a中调用fun(1)。
 * 上面已经分析了,a有一个属性,属性值为函数对象,函数对象中的n=0
 * (后面可能会有点晕,我们慢慢来分析)
 * 因此这里再调用fun(1)时,会执行return fun(m,0)这个语句,!!再次调用了fun()!!
 * 实际传参后调用的函数是:fun(1,0),这个怎么运行呢?
 * 1.传入参数n=1, o=0
 * 2.输出o
 * 3.返回
 * {
        fun:function(m) {
            return fun(m,n);   //用上面的解释,这里的n=1
        }
    }
 * 注意:在a中,返回的这个对象可能没多大用,是混淆你的,但对后面b和c的理解至关重要
 * 与var a = fun(0)不同的是,在a.fun(1)执行完毕后,因为没有持续对a.fun(1)它本身进行引用
 * a.fun(1)在执行完毕后就释放内存了,因此它所返回的(或者说改变的)n值没有保存
 * ----------------------------------------------------------------------------- *
 * a.fun(2) a.fun(3)
 * 由于上面的a.fun(1)没有能够保存n值,因此a.fun(2)和a.fun(3)的调用过程和a.fun(1)
 * 除了在参数上有不同外,其余都相同,结果最后也是输出0
 *
 * / *
 * var b = fun(0).fun(1).fun(2).fun(3)
 * 我们继续一步步来分析。
 * 第一层:fun(0) 过程和上面的 var a = fun(0)一模一样
 * 第二层:fun(0).fun(1) 过程和上面 a.fun(1)一样,但结果不同,后面会说
 * 第三层:fun(0).fun(1).fun(2)
 * 解析:
 * 在上面a的例子中,执行完fun(0).fun(1)后,虽然返回了一个对象,但是因为没有继续保持
 * 对它本身的引用,运行之后就释放内存了;但是在b中,在fun(0).fun(1)本身身上再调用fun(2)。
 * 因此此时调用fun(2)的环境是这样的:
 * {
        fun:function(m) {
            return fun(m,1);   // m=2
        }
    }
 * 再简要分析一下运行过程
 * 1.传参,n=2, o=1
 * 2.输出o
 * 3.返回
 * {
        fun:function(m) {
            return fun(m,2);
        }
    }
 * 这次的返回值是否一直保存在内存中取决于后面是否还有它的引用,而后面刚好还要调用fun(3)
 * 所以这个返回值也是作为fun(3)的调用环境。
 * 我们继续。
 * 第四层:fun(0).fun(1).fun(2).fun(3)
 * 解析:
 * fun(3)的执行环境:
 * {
        fun:function(m) {
            return fun(m,2);   // m=3
        }
    }
 * 1.传参,n=3, o=2
 * 2.输出o
 * 3.返回
 * {
        fun:function(m) {
            return fun(m,3);
        }
    }
 *  *
 * 相信看到这里多少有点自己的理解了,这个c可以作为测试自己的理解程度
 *  *
 * 下面是我的理解:
 * var c = fun(0).fun(1)
 * 看到这样对函数使用一个变量保存,可以认为这个环境是暂时不变的,
 * 后面c调用的函数都是在它基础上调用的,因此我可以选择记住这个状态
 * 从头分析,fun(0)输出了undefined,返回了一个对象,这个对象有fun属性,值为一个函数对象,
 * 该函数对象m值为参数,n值为父级函数的参数,值为0;
 * 然后再看看fun(0).fun(1),在上面环境中调用fun(1),结果就是输出了0,
 * 并将m值作为返回对象里的n保存在返回对象中。这就是后面调用的环境。
 *
 * 最后总结出c后面两次调用,不管参数时什么,它都只是作为返回对象中的n保存在返回对象中,
 * 对当前输出有影响的是上一个传入的参数,所以一直都是输出1
 *
 * PS.上面说的“环境”其实就是闭包,但是我本人并不十分理解,才选择用容易理解的“环境”代替闭包,
 * 告诉日后可能忘记闭包的自己,闭包的理解的是什么。如果有幸有大牛能看到,恳请指出错误!!
 *
 * **/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值