博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
简单说 一道JS闭包面试题
阅读量:6090 次
发布时间:2019-06-20

本文共 2939 字,大约阅读时间需要 9 分钟。

说明

最近看到这样一段代码

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();    //1fun1();    //报错 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的值为0        console.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的值为0        console.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 2  var c = fun(0).fun(1); c.fun(2); c.fun(3);//undefined 0 1 1

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

顺便推荐几篇讲解闭包的文章

转载地址:http://gpmwa.baihongyu.com/

你可能感兴趣的文章
Linux中的帮助功能
查看>>
针对Android的Pegasus恶意软件版本和针对iOS的有什么不同?
查看>>
全局探色器
查看>>
Hive Export和Import介绍及操作示例
查看>>
http://mongoexplorer.com/ 一个不错的 mongodb 客户端工具。。。
查看>>
上传jar包到nexus私服
查看>>
Why Namespace? - 每天5分钟玩转 OpenStack(102)
查看>>
Project:如何分析项目中的资源分配情况
查看>>
HDU 4803 Poor Warehouse Keeper (贪心+避开精度)
查看>>
小错误汇总
查看>>
Spring源码系列 — Envoriment组件
查看>>
java正则表达式去除html标签,Java中正则表达式去除html标签
查看>>
使用Cobbler批量部署Linux操作系统
查看>>
zabbix企业应用之服务端与客户端的安装
查看>>
实例讲解遗传算法——基于遗传算法的自动组卷系统【理论篇】
查看>>
无法在web服务器上启动调试。调试失败,因为没有启用集成windows身份验证
查看>>
Bat相关的项目应用
查看>>
Django为数据库的ORM写测试例(TestCase)
查看>>
NYOJ-107 A Famous ICPC Team
查看>>
与众不同 windows phone (44) - 8.0 位置和地图
查看>>