由于最近在学习关于闭包相关的知识, 并且闭包这个知识点让我有点搞不太清楚其具体的定义, 所以在网上也查阅了很多大佬的讲解和对闭包的一个定义.
最后感觉还是 MDN 上的说法感觉比较好理解一些, 对闭包还是不太理解的道友可以尝试看一看.
MDN 上是这样说的: 闭包是函数和声明该函数的词法环境的组合
原地址:
在了解闭包的过程中遇到一个很多地方都出现的一个面试题, 按照自己的想法想了下发现几乎没对... 所以就花了些时间分析了一下, 供自己以后忘记了可以回顾一下.
同时, 如果这里依旧存在一些误区, 希望各位大佬们在评论区帮忙指正, 感激万分!
原题如下:
- 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); // ?
- var b = fun(0).fun(1).fun(2).fun(3); // ?
- var c = fun(0).fun(1); // ?
- c.fun(2); // ?
- c.fun(3); // ?
有兴趣的道友们也可以试着先想一想答案, 看下是否一致?
以下是解题思路:
1. 首先我对这个题画了下题目中两个 fun 函数中的一些信息 (可能不太完整, 但是解题应该够用了)
2. 当执行 var a = fun(0); 时, 内存中开辟了一块新的空间给这个新的对象, 这个对象中定义了一个方法 fun. 并且在 fun(0)执行时, 在当前作用域下的变量信息如下:
因此, 当该语句执行时, 控制台打印的值为 undefined
3. 当执行 a.fun(1) 时, 因为对象 a 中的 fun 方法在定义时所处的环境 ( [[scope]] ) 中存在一个变量 n 和变量 o,
并且在这条语句执行的时候, 变量 n( 此时 n 的值为 0 ) 被第三方 (除了函数 fun 和方法 fun)引用了, 也就是被外部的对象 a 引用了, 因此产生了 Closure(闭包).
然后, 这条语句的 return 执行的时候先执行 调用 fun 函数 ----> 把 m 的值传递给了 fun 函数中的 n, 把 n 传递给了 fun 函数中的 o, 因此控制台中打印 o 的结果为 0.
然而事情并没有结束, 调用 fun 函数会返回一个新的对象, 这个对象也会在内存中新开辟一个空间, 而此时这个新对象中的方法 fun 被定义时所处环境中的变量 n 已经被赋值为 m 的值, 也就是 1 了.
4. 当 a.fun(2)执行的时候, 发生了和上面一样的故事, 并且内存中又被返回了一个新的对象且这个新对象中的方法 fun 被定义时所处环境中的变量 n 已经被赋值为 m 的值, 也就是 2
5. a.fun(3)执行同上, 且这个新对象中的方法 fun 被定义时所处环境中的变量 n 已经被赋值为 m 的值, 也就是 3
故: a.fun(2) 和 a.fun(3) 在控制台中打印 o 的结果都为 0, 且不管你传的参数是多少, 只要你没有改变 a 对象的值, 那么输出的结果都是 0, 因为你传的参数都存在新的对象中了.
当时我这里存在一个疑问, 每次执行 n 的值不是都被修改了吗, 为什么结果都是 0 呢?
注意: 因为你始终都是在调用 a 的方法, 而你每次执行 a 的方法 fun 的时候又没有把新返回的对象重新赋值给 a, 所以 a 里面的 fun 方法被定义时所处环境中的变量 n 一直都是 0
6. 当 var b = fun(0).fun(1).fun(2).fun(3); 执行的时候就和上面疑问中的情形是一样的了.
当 fun(0)执行的时候, 同上面 a.fun(0)一样, 返回结果是 undefined, 且此时产生的新对象中, 方法 fun 被定义时所处环境中的变量 n 为 0
当 fun(1)执行的时候, 相当于上面的 a.fun(1)一样, 都是输出 0 (此时 fun 方法所处环境中的 n 为 0), 且返回一个新对象, 新对象中的变量 n 为 1
当 fun(2)执行的时候, 就不太一样了, 因为是在前一条语句执行结果后面直接调用 fun 方法, 但此时的 fun 方法已经不再是 fun(1)中的方法了, 而是上面返回的新对象中的方法, 也就是变量 n 为 1 的方法, 所以, 这里输出的结果为 1, 且返回一个新对象, 新对象中的变量 n 为 2
当 fun(3)执行的时候, 和 fun(2)的情况一样, 输出结果为新的对象中的 n, 也就是 2
7. 到这里, var c = fun(0).fun(1); 应该就能够明白为什么这里输出对的结果是 undefined 和 0 了
因为道理和前面一样, 第一个 fun(0) 给 n 传递了值, 但是 o 没有, 所以打印 o 的结果为 undefined, 第二个 fun(1) 将 n 的值传给了 o, 所以打印的结果为 0, 且这里产生的对象被赋值给了变量 c, 此时方法 fun 被定义时的环境 (也就是它的词法作用域) 中的 n 是被重新赋值的 1 (方法 fun 的形参 m 把被传过来的实参 1, 传递给了函数 fun 中的形参 n)
故: c.fun(2) 和 c.fun(3)中 c 对象的 fun 方法被定义时的环境中的 n 都是 1, 所以输出的结果也是把 n 的值传递给 fun 函数中的 o, 即输出 1
此处是测试结果图:
来源: https://www.cnblogs.com/ViavaCos/p/11511171.html