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

最后感觉还是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. PHP命令行常用参数说明和使用

    -i 打印phpinfo命令 root@DK:/mnt/hgfs/cpp/php# php -i | grep session -v 输出php版本信息 root@DK:/mnt/hgfs/cpp/p ...

  2. P1902 刺杀大使

    题目描述 伊朗伊斯兰革命卫队(某恐怖组织)正在策划一起刺杀行动,他们的目标是沙特驻美大 使朱拜尔.他们来到了沙特驻美使馆,准备完成此次刺杀,要进入使馆首先必须通过使馆前 的防御迷阵. 迷阵由 n*m ...

  3. 2、Apache(httpd)之一 三种工作模式

    httpd的特性: 高度模块化:core + modules 模块化设计DSO:Dynamic Shared Object MPM:Multipath Processing Modules 多路处理模 ...

  4. WSL2(Ubuntu)安装Postgres

    原文链接:https://www.xu.ci/2019/12/wsl2ubuntupostgres.html 原文作者:博客园--曲高终和寡 *******************如果你看到这一行,说 ...

  5. 新建Class文件时,添加作者版权注释声明

    以安装路径C盘为例,各版本路径如下: VS2015:C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\ItemTempla ...

  6. tecplot-云图中显示等值线的值

    原版视频下载地址:https://yunpan.cn/cx6IQkkYKIB99  访问密码 a3ee

  7. 数据结构Java版之递归与迭代算法(五)

    递归的概念很简单,就是自己调用自己. 而迭代,则是通过修改初始化数据,得到中间结果,然后不断的对中间结果进行修改,而得到最终结果.简单来说迭代就是循环. 在此,我们用一个比较经典的Fibonacci数 ...

  8. JAVA的日期类DATE

    好记性不如烂笔头. 1:常见场景  字符串转时间格式,日期转换字符串(在前后端交互 json) 导入包(好像我的IDEA 不知道装了什么插件 会自动补齐提示) import java.text.Par ...

  9. MYSQL 神奇的操作insert into test select * from test;

    将16行数据复制一份插入数据库,变成32行

  10. cmd命令net和sc

    来看windows中启动和关闭服务的方法:在cmd下可有两种方法打开,分别是net和sc. 1.net用于打开没有被禁用的服务, NET命令是功能强大的以命令行方式执行的工具. 它包含了管理网络环境. ...