js闭包面试题经典_js闭包原理

js闭包面试题经典_js闭包原理说明最近看到这样一段代码functionfun(n,o){console.log(o);return{fun:function(m){returnfun(m,n);}};}vara=fun(0);a.fun(1);a.fun(2);a.fun(3);varb=f

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

说明

最近看到这样一段代码

 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的值为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://www.cnblogs.com/xxcanghai/p/4991870.html

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

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

这里写图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/179252.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 使用Depix进行马赛克的消除测试

    使用Depix进行马赛克的消除测试0.前言最近看到各种公众号都在推一个叫Depix的Github项目,用途是能够消除文字马赛克,抱着试试看的态度测试了一下这个项目。太长不看版:公众号对该项目的效果有一定程度的夸大,但是还是要注意使用各种方法对个人隐私进行保护项目地址:https://github.com/beurtschipper/Depix项目自带的Example如下:这个项目的文档上说,只需要马赛克后的图像,马赛克图像上包含的字符的DeBruijn序列,就可以生成去马赛克的图像。(测试效果如上图所示)接下来就测试一

  • Android——谷歌官方下拉刷新控件SwipeRefreshLayout「建议收藏」

    Android——谷歌官方下拉刷新控件SwipeRefreshLayout「建议收藏」转自:http://blog.csdn.net/zouzhigang96/article/details/50476402前言: 如今谷歌推出了更官方的下拉刷新控件,这无疑是对安卓开发人员来说是个好消息,很方便的使用这个SwipeRefreshLayout控件实现下拉刷新功能。Android4.0以下的版本需要用到android-support-v4.jar包才能用到 andr

  • mac linux 虚拟机(虚拟机的ubuntu怎么连不上网)

    查看原文1.设置虚拟机网格为 NAT模式2.在Mac系统里打开终端(快捷键:Ctrl+Alt+T),输入ifconfig,查看Mac机的ip3.进入虚拟机设置网络,手动配置IPv4,xxx.xxx.xxx.2是固定的路由及DNS的ip4.关闭网络再打开即可访问外网5.结果

  • android singleTask

    android singleTask本文载自http://blog.csdn.net/wang_zun_ren/article/details/6823257现有2个项目,taskA、taskB。taskA负责调用taskB中指定的界面。taskB中有3个界面,a、b、c,每个界面显示它所在的taskid。SingleTask:其中b界面被声明为SingleTask。先运行tas

  • VBoxManage 命令详解 (有用)「建议收藏」

    VBoxManage 命令详解 (有用)「建议收藏」查看当前虚拟机VBxoManagelistvms查看当前正在运行的虚拟机VBoxManagelistrunningvms启动虚拟机VBoxManagestartvm虚拟机名无前端图形界面方式启动虚拟机VBoxManagestartvm虚拟机名–typeheadless使用VRDP方式通过命令行启动虚拟机:(3389)VBoxManag

  • linux查看节点使用情况_linux生成ssh密钥

    linux查看节点使用情况_linux生成ssh密钥说明:目前安装了4个Redhatlinux操作系统,主机名分别为hadoop01,hadoop02,hadoop03,hadoop04其中hadoop01为主节点hadoop01,其余为hadoop02,hadoop03,hadoop04为从节点四个节点ip地址为192.168.10.61~64.如果不修改hosts文件,从第二部开始可将hadoop01~04改

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号