博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【前端芝士树】Js中的闭包是怎么一回事 && 笔试问题集锦
阅读量:7041 次
发布时间:2019-06-28

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

【前端芝士树】Js中的闭包是怎么一回事 && 笔试问题集锦

为什么会有闭包的出现?

这涉及到var作为变量声明的关键词时所出现的一些问题。

比如,var 的 变量提升 以及 函数级作用域

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。
另一方面,在函数外部自然无法读取函数内的局部变量。

需要注意的是,如果在函数内部声明变量时没有使用var关键词,实际上声明的是一个全局变量,如下:

function f1(){    n = 999;}//console.log(n); // ReferenceError: n is not definedf1();console.log(n); // 999

这里为什么第一处会报错呢?关于这个问题下面有比较基础的解释:

JS的解析过程分为两个阶段:预编译期(预处理)执行期

  • 预编译期 JS会对本代码块(两个script块互不影响)中的所有var声明的变量和函数进行处理(类似与C语言的编译)
    此时处理函数的只是声明式函数,而且变量也只是进行了声明但未进行初始化以及赋值。>
  • 执行期 会按照代码块的顺序筑行执行

正因为从外部访问在函数内部进行声明的局部变量是不可能的,所以出现了闭包这种形式,在函数内部再定义一个函数。

闭包(Closure)是什么?

查阅了一些文章和资料,发现还是下面的定义最容易理解:

闭包:定义在函数内部的一个函数。

扩展一些讲,可以参考一下阮一峰的讲解:

闭包:能够读取其他函数内部变量的函数。

俗话说的好,看定义不如看代码更直观一些,如下

function f1(){    var n=999;    function f2(){        console.log(n);    }    return f2;}var result=f1();result(); // 999

如此段代码所示,f2()就是其中的闭包函数,通过f2()我们可以访问到f1()内部的n

更常见的一种简写形式:

function f1(){    var n=999;    return function(){        console.log(n);    };}var result=f1();result(); // 999

闭包的优缺点

优点:

  1. 可以读取函数内部的变量
  2. 让这些变量的值始终保持在内存中。

缺点:

  1. 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
  2. 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

闭包面试题集锦(持续更新)

问题一、简单闭包

var a = 1;function foo(){    var a = 2;    c = 0;    return function () {        console.log(a);        console.log(b++);        console.log(c);    }}console.log(a);// 1//console.log(c); // Reference Errorvar b = 3;var x = foo();x(); //2 3 0console.log(a); // 1console.log(b); // 4console.log(c); // 0

问题二、闭包的链式调用

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);
看解答前先思考一下会输出什么哦

【解答】: 首先对函数进行分析,这个函数其实是返回了一个对象,{fun:function(){}},里面有一个函数作为属性,这个函数就是闭包,使得函数内部的变量保留在内存中。

注意,这里会有一个可能误解的地方,return {fun:...}里面的fun是fun(n,o)吗?明白这个区别后后面就容易多了。

好了,明白大概的原理后,我们来分析这个问题:

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

执行a = fun(0),0是作为n传入的,o没有参数传入,所以输出undefined,之后,

a = {  fun:function(m){     return fun(m,0);//这里的n应该变成了第一次调用时的参数n,也就是0  }}也就是a = { fun:function(m){     return function(n = m, o = 0) {         console.log(o) //输出0         return {            fun:function(m){              return fun(m,n);            }          };    };  }}

所以无论传入的m是什么,输出永远都是0

最后,输出结果如下

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

搞清楚第一个的过程,第二个的破解关键就在于闭包让函数内部的变量始终保存在内存之中。

//bundefined012//cundefined011

参考文章

《闭包 - 廖雪峰的官方网站》

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

你可能感兴趣的文章
微信小程序 常见问题 小结
查看>>
少用数字来作为参数标识含义
查看>>
不错位的java .class 反编译工具推荐
查看>>
SQLServer 数据库镜像+复制切换方案
查看>>
平安科技移动开发二队技术周报(第十五期)
查看>>
build.gradle & gradle.properties
查看>>
windows server2008服务器下XAMPP集成环境配置apache的SSL证书:
查看>>
JS中同步与异步的理解
查看>>
Django Rest Framework(分页、视图、路由、渲染器)
查看>>
总是容易忘记:enum、int、string之间的快速转换
查看>>
002-localStorage和sessionStorage操作
查看>>
Deepin-添加path
查看>>
设计模式-行为型模式,观察者模式(13)
查看>>
Win8 Metro(C#)数字图像处理--2.41彩色图像密度分割算法
查看>>
Intellij IDEA查看所有断点
查看>>
Top K算法
查看>>
CentOs6.7 python2.6升级到2.7.11
查看>>
JavaBridge
查看>>
.NET MVC JSON JavaScriptSerializer 字符串的长度超过 maxJsonLength 值问题的解决
查看>>
statickeyword
查看>>