由于最近在学习关于闭包相关的知识,并且闭包这个知识点让我有点搞不太清楚其具体的定义,所以在网上也查阅了很多大佬的讲解和对闭包的一个定义。

最后感觉还是MDN上的说法感觉比较好理解一些,对闭包还是不太理解的道友可以尝试看一看。

MDN上是这样说的:闭包是函数和声明该函数的词法环境的组合

原地址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

在了解闭包的过程中遇到一个很多地方都出现的一个面试题,按照自己的想法想了下发现几乎没对...所以就花了些时间分析了一下,供自己以后忘记了可以回顾一下。

同时,如果这里依旧存在一些误区,希望各位大佬们在评论区帮忙指正,感激万分!

原题如下:

        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

此处是测试结果图:

图解JavaScript闭包面试题的更多相关文章

  1. JavaScript 闭包 面试题

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...

  2. 你不一定能做对的JavaScript闭包面试题

    由工作中演变而来的面试题 这是一个我工作当中的遇到的一个问题,似乎很有趣,就当做了一道题去面试,发现几乎没人能全部答对并说出原因,遂拿出来聊一聊吧. 先看题目代码: function fun(n,o) ...

  3. javascript前端面试题及答案整理

    Part1 手写代码 现场手写代码是现在面试中很常见的一类面试题,考察基础的数据结构与算法能力. 1 数组去重的实现 基本数组去重 Array.prototype.unique = function( ...

  4. 《Web 前端面试指南》1、JavaScript 闭包深入浅出

    闭包是什么? 闭包是内部函数可以访问外部函数的变量.它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量. 内部函数不仅可以访问外 ...

  5. JavaScript 闭包深入浅出

    闭包是什么? 闭包是内部函数可以访问外部函数的变量.它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量. 内部函数不仅可以访问外 ...

  6. JavaScript闭包(Closure)

    JavaScript闭包(Closure) 本文收集了多本书里对JavaScript闭包(Closure)的解释,或许会对理解闭包有一定帮助. <你不知道的JavsScript> Java ...

  7. Javascript闭包和C#匿名函数对比分析

    C#中引入匿名函数,多少都是受到Javascript的闭包语法和面向函数编程语言的影响.人们发现,在表达式中直接编写函数代码是一种普遍存在的需求,这种语法将比那种必须在某个特定地方定义函数的方式灵活和 ...

  8. 图解Javascript原型链

    本文尝试阐述Js中原型(prototype).原型链(prototype chain)等概念及其作用机制.上一篇文章(图解Javascript上下文与作用域)介绍了Js中变量作用域的相关概念,实际上关 ...

  9. javascript闭包理解

    //闭包理解一 function superFun(){ var _super_a='a'; function subfuc(){ console.log(_super_a); } return su ...

随机推荐

  1. 阿里开源线上应用调试利器 Arthas的背后

    Arthas是一个功能非常强大的诊断工具,功能点很多,例如:jvm信息.线程信息.搜索类中的方法.跟踪代码执行.观测方法的入参和返回参数等等. 作为有追求的程序员,你不仅要知道它能做什么,更要思考它是 ...

  2. 洛谷 P3258 [JLOI2014]松鼠的新家 题解

    P3258 [JLOI2014]松鼠的新家 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他 ...

  3. 部署Hadoop集群之前的一些系统配置

    修改内核参数 在/etc/sysctl.conf文件中添加如下配置(需要root权限)以下参数的默认值是在centos7下查看的fs.file-max = 6815744 //文件描述符总数,默认值: ...

  4. [代码审计]php弱类型总结

    0x01 前言 php是世界上最好的语言,所以php自身的安全问题也是web安全的一个方面.由于其自身弱类型语言的特性以及内置函数对于传入参数的松散处理,所以会带来很多的问题,这里将进行简要介绍. 弱 ...

  5. Barman 安装

    Barman需要用到psql客户端,所以需要在Barman服务器安装psql数据库 1 linux操作系统环境准备: python版本:2.6或2.7 yum -y install epel-rele ...

  6. MYSQL | ERROR 1305(42000) SAVEPOINT *** DOES NOT EXIST

    autocommit模式:在开启情况下,对于每条statement来说,都会自动形成一个commit,也就是会即时对开始和结束一个事务.所以,当出现rollback to savepoint出现这个错 ...

  7. vue中样式被覆盖的问题

    在我们引入外部的样式时,发现自己无论如何都改不了外部的样式,自己的样式老被覆盖,究其原因还是我们的 外部样式放的位置不对 main.js 我们应该在 main.js 的开头引入样式,这样的话就不存在覆 ...

  8. Vue导出ZIP

    Export2Zip /* eslint-disable */ require('script-loader!file-saver'); import JSZip from 'jszip' expor ...

  9. linux下phpmailer发送邮件出现SMTP ERROR: Failed to connect to server: (0)错误

    转自:https://www.cnblogs.com/raincowl/p/8875647.html //Create a new PHPMailer instance $mail = new PHP ...

  10. Python带参数的函数装饰器

    # -*- coding: utf-8 -*- # author:baoshan # 带参数的函数装饰器 def say_hello(country): def wrapper(func): def ...