说明

最近看到这样一段代码

 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);//问:三行a,b,c的输出分别是什么?

觉得有点意思,和大家一起来聊聊。
我相信如果你不是非常理解JavaScript中的闭包,一定是不想看这段代码的。

解释

好的,我们暂时先不去想这段代码,先看点简单的

function fun0(){var a=1;console.log(a);
}
function fun1(){console.log(a);
}
fun0(); //1
fun1(); //报错 a is not defined

这段代码,我相信大家应该知道最后为什么结果会是 1 和 报错 的,在函数内声明的变量只在函数体内定义,它们是局部变量,作用域是局部的,所以 函数 fun1 调用后,找不到a,就报错了,JavaScript采用词法作用域,函数的执行依赖于变量作用域,这个作用域是在函数定义时决定的,所以我们只要改改上面函数 fun1的位置,它就不会报错了。

function fun0(){var a=1;console.log(a);//把fun1放在fun0中,就不报错了function fun1(){console.log(a);}fun1();   //1
}
fun0();   //1

代码改成这样,只是把fun1 放在 fun0 中就不报错了,函数调用后都输出1

好了,我们来看最开始提到的代码,先简化一下

function fun(n,o){return {}
}

我们先看这段代码,fun 调用后会怎么样?
很明显会返回一个空对象,记住,fun调用后会返回对象,这点很重要。

 function fun(n,o){console.log(o);return {fun:function(m){return fun(m,n);}};}var a = fun(0);

这里提一句,当调用函数的时候传入的实参比函数声明时指定的形参个数要少,剩下的形参都将设置为undefined值。
console.log(o); 输出undefined
var a = fun(0); 那a是值是什么,是fun(0),返回的那个对象

{fun:function(m){return fun(m,0);}
}

这个对象,有一个fun的方法,方法返回的结果就是最外面 fun 调用的结果。


var a=fun(0),传入一个参数0,那就是说,函数fun中参数 n 的值是0了,而返回的那个对象中,需要一个参数n,而这个对象的作用域中没有n,它就继续沿着作用域向上一级的作用域中寻找n,最后在函数fun中找到了n,n的值是0,这段话是本文的重点, 明白这段,那问题就容易解决了。

说到这里,这道题基本上可以解决了,希望大家能听明白我上面说的话,下面的就简单了。我们一步一步看。

现在我们知道 a 是

{fun:function(m){return fun(m,0);}
}

这样的一个对象
a.fun(1); 会怎么样?看代码

{fun:function(1){return fun(1,0);}
}

a.fun(1); 返回的结果,就是 fun(1,0),返回的结果

 function fun(n,o){ //n的值为1,o的值为0console.log(o);return {fun:function(m){return fun(m,n);//n的值为1}};
}
fun(1,0);  //输出0,并返回一个对象,这个对象有一个fun的方法,这个方法调用后,会返回外层fun函数调用的结果,并且外层函数的第二个参数是 n 的值,也就是1  

a.fun(2); 会怎么样?看代码

{fun:function(2){return fun(2,0);}
}

a.fun(2); 返回的结果,就是 fun(2,0),返回的结果

 function fun(n,o){ //n的值为2,o的值为0console.log(o);return {fun:function(m){return fun(m,n); //n的值为2}};
}
fun(2,0); //输出0,并返回一个对象,这个对象有一个fun的方法,这个方法调用后,会返回外层fun函数调用的结果,并且外层函数的第二个参数是 n 的值,也就是2  

a.fun(3); 就不说了,一样的。

var a = fun(0); a.fun(1); a.fun(2); a.fun(3);
var b = fun(0).fun(1).fun(2).fun(3);

我们继续说b,b和a的不同在于,var a = fun(0); 之后一直用的是a这个对象,是同一个对象,而b每次用的都是上次返回的对象。
如果改成这样

var a = fun(0); a=a.fun(1); a=a.fun(2); a=a.fun(3);
var b = fun(0).fun(1).fun(2).fun(3);

把返回的对象,重新赋值给a,这样两行的结果就是一样的了。
var c = fun(0).fun(1); c.fun(2); c.fun(3);
c 与他们的不同,只是var c = fun(0).fun(1); 之后用的是同一个对象罢了。

总结

说下结果

var a = fun(0); a.fun(1); a.fun(2); a.fun(3);
//undefined 0 0 0 var b = fun(0).fun(1).fun(2).fun(3);
//undefined 0 1 2var c = fun(0).fun(1); c.fun(2); c.fun(3);
//undefined 0 1 1

最开始的代码来自这里
http://www.cnblogs.com/xxcanghai/p/4991870.html

这篇文章只是针对这道题讲了讲,没有非常着重的去讲闭包这个概念,所以如果朋友们,对闭包详细的概念还不是很理解,要赶紧学习了。
顺便推荐几篇讲解闭包的文章

学习Javascript闭包(Closure)
Javascript闭包——懂不懂由你,反正我是懂了
JS闭包可被利用的常见场景

简单说 一道JS闭包面试题相关推荐

  1. 分享 10 个 JS 闭包面试题(图解),进来看看你能答对多少

    英文 | https://betterprogramming.pub/10-javascript-closure-challenges-explained-with-diagrams-c9641108 ...

  2. 一道JS算法面试题——冒泡、选择排序

    JS排序算法 基础排序 冒泡排序 选择排序 面试题 基础排序 今天学习了数据结构,遇到了一个关于算法的面试题,然后从中想到了冒泡排序和选择排序对一个数组从小到大的排序的方法,今天分享给大家,顺便记录下 ...

  3. 每天一道js基础面试题

    js的基本数据类型有哪些? Number,String,Boolean,Null,Undefined,Symbol,BigInt

  4. 前端面试题 HTML5 CSS3(盒子模型、盒子水平垂直居中、经典布局) JS(闭包、深浅克隆、数据劫持和拦截) 算法(排序、去重、数组扁平化) Vue(双向数据绑定原理、通信方式)

    前端面试题 HTML5 相关面试题 CSS3 相关面试题 盒子模型 盒子水平垂直居中的方案 经典布局方案 圣杯布局 双飞翼布局 flex布局 定位方式布局 css实现三角形 JS 相关面试题 8种数据 ...

  5. 简单理解js闭包、类型引用....第一章

    js 闭包函数.类型引用.this指向.对象原型链...这些东西让我们对js又爱又恨!js虐我千百遍,我待js如初恋. 很多初学者一开始会觉得这些概念没什么用,导致对这些东西产生一种抵抗力.接下来我们 ...

  6. 历史上最简单的一道Java面试题,但无人能通过

    作者:方志宏 来源:zhuanlan.zhihu.com/p/57859872 这可能是历史上最简单的一道java面试题了. 题目很简单,完成代码,判断一个整数是否是奇数: public boolea ...

  7. JS闭包+常见面试题

    scope作用域 .Closure闭包对象 可以借助chrome调式工具查看闭包对象 注意:function声明存在变量提升,所以22行已经存在闭包对象了: 闭包产生的条件: 函数嵌套: 嵌套的内部函 ...

  8. js经典面试题50道

    js的面试题 1. javascript的typeof返回哪些数据类型. 答案:string, boolean, number, undefined, function, object ,es6新增s ...

  9. JS闭包的理解及常见应用场景

    JS闭包的理解及常见应用场景 一.总结 一句话总结: 闭包是指有权访问另一个函数作用域中的变量的函数 1.如何从外部读取函数内部的变量,为什么? 闭包:f2可以读取f1中的变量,只要把f2作为返回值, ...

最新文章

  1. Go-技篇第一 技巧杂烩
  2. python新手入门讲解-这是大多数新手入门之后强烈推荐的python自学入门指南秘笈...
  3. 在 Linux 下运行 ASP.NET 2.0
  4. 真人秀制作网站_[BoA] 出道20周年真人秀Nobody Talks To BoA上演与李秀满总制作人充满默契的对话!...
  5. 8.使用Xshell5密钥登录liunx
  6. OWC做电子表格和图表的试验
  7. 《代码敲不队》第三次作业:团队项目的原型设计
  8. php搜索文件名,PHP搜索文件且列出文件名的代码参考
  9. asp. net sqlsever旅游管理系统动态网站设计制作作业成品
  10. 《写给程序员的数据挖掘实践指南》——5.2. 10折交叉验证的例子
  11. 计算机管理员英语怎么说,电脑管理员英文administrator写法
  12. ectouch2.0 php5.5_Ectouch2.0 分析解读代码审计流程
  13. 游程编码用matlab实现代码_matlab游程编码
  14. 树莓派的蓝牙通讯(bluez、gattlib)
  15. python爬虫之xpath解析(附实战)
  16. 明源云预计年亏超7亿元:被花旗下调评级,“人脸识别”遭质疑
  17. CentOS7使用mount命令来挂载CDROM
  18. 电脑现在找不到驱动器,设备管理器显示DVD/CD-ROM驱动器是黄色感叹号
  19. 二线法和四线法测量电阻的原理及区别
  20. Zebra BI for Excel

热门文章

  1. 使用pysam读取DNA序列
  2. 原生JavaScript实现团购——限时抢
  3. java熔断器_一种熔断器的实现方法与流程
  4. Vitamio的使用
  5. 列车实时数据通信协议(TRDP)探索之路【三】
  6. stm32全彩LED屏显示
  7. 17岁高中生证明著名数学难题,因此被MIT录取
  8. 分号与逗号的区别及举例_顿号和逗号的区别
  9. 在线教育网站如何更好的实现视频安全视频保护?
  10. 【数学分析】一致连续的一些证明方法