话不多说,直接贴代码,阐述都在注释中,有幸有大牛看到的话,恳请指正错误!
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.上面说的“环境”其实就是闭包,但是我本人并不十分理解,才选择用容易理解的“环境”代替闭包,
* 告诉日后可能忘记闭包的自己,闭包的理解的是什么。如果有幸有大牛能看到,恳请指出错误!!
*
* **/