资讯专栏INFORMATION COLUMN

日了哈士奇系列之JavaScript闭包

AWang / 1205人阅读

摘要:闭包闭包,目前还没有统一的定义。展开这个对象果然是世界上最好的浏览器,给我们展示了闭包中访问的变量。模块化的始祖据笔者所了解,模块化就是借用闭包来实现的。所以我们在开发过程用要慎用闭包。

标题为什么叫日了哈士奇?因为闭包这个东西已经在我脑海里萦绕了很久,大概有多久呢?(掰手指头和脚指头ing....) 大概是笔者从事前端工作的第一个月开始吧......仍记得那个时候还请教了公司的大神,不过只怪当时脑袋不好使,反正就是没听懂啊喂!不过最近项目没那么忙,就回头研究这个前端亘古不变得话题之一:闭包。诚然,闭包对于JavaScript初学者而言理解起来稍许有点吃力,不过我相信即使是初学者看了本篇博客,也会被闭包有更深的认识(“王婆卖瓜,自卖自夸”),hahah...废话不扯了,赶紧开始吧。

话题引入

在开始介绍闭包之前呢,笔者先墨迹下。大家先来思考这样一个问题:

如何从函数A外部访问函数A内的变量?

不了解闭包的朋友可能会认为这是一个愚蠢得像土拨鼠系列的问题,就是一个字:扯淡 (手动滑稽)。即使这样子,笔者还是不知廉耻得贴出上一篇博客的地址,因为这篇博客对解决这个问题有很大的帮助。下面就一起思考如何回答上述的问题:
根据上篇博客的描述,要想访问一个变量,那么必定要在这个变量的作用域内访问;其次,对于访问函数中的变量,那只能在函数中做点事(手)情(脚),比如这样:

function closure() {
    let name = "Husky";
    let age = 2;

    //access variable
}

那么既然已经在函数中访问到了,那又如何才能实现在函数外访问到呢?答案是肯定是,只要再做点事(手)情(脚)就好了,不过先不急着思考怎么办,下面给大家形象化一个非(丧)常(心)有(病)趣(狂)的情景:
隔壁老王啊是个房东,今天有个美女要租他的房子。美女真是一(胸)身(大)正(臀)气(翘),于是老王想借此机会观(偷)察(窥)一番。无奈每天晚上房间的门窗都被关得严严实实根本没从下眼,老王就偷偷在里面安装了摄像头,然后就肆无忌惮了...(手动滑稽)
情景描述完了,不过朋友们不要想入非非,毕竟笔者一身正气啊喂!
改一下上面的代码来将上述情景表达出来:

function Room() {
    let beauty = "如花";

    //摄像头
    
}

那么摄像头可以在房间里捕(访)捉()房()间()内()的影()像(),同时还能把捕捉到的情景传回到老王的屏幕上。因此可以联想到,我们在函数中放置一个对象然后在对象中访问变量并且把这个对象return出去,我们再接收返回回来的对象后不就可以在外面访问变量了嘛!Bingo...就是这样。
俗话说,JavaScript世界中万物皆对象(函数也是对象)。所以我们可以这样补充上面的代码:

function Room() {
    let beauty = "如花";

    //摄像头
    let camera = function() {
        return beauty;
    }
}

这样我们就能获取到一个函数,相当于摄像头的信号线,通过这个就可以获取到影像咯:

function Room() {
    let beauty = "如花";

    //摄像头
    let camera = function() {
        return beauty;
    }

    return camera`请输入代码`;
}

let camera = Room();

let beauty = camera();

console.log(`老王看到 ${beauty} 啦`);

看下运行结果:

然后我们就帮助老王如愿以偿得看到了如花并且继续每晚不可描述的事。(看我一脸正气...)

说到这,闭包这个玩意儿已经浮出水面。

闭包
闭包,目前还没有统一的定义。单就笔者的理解就是:闭包是一个体系,由函数体中的变量和访问该变量的函数组合而成。

对应上述的代码就是:beautycamera
闭包只是这类体系的名字,其英文名是Closure;闭包其实并没有关闭的意思,相反它还向外暴露内部的变量只不过是通过一定的约束方式(函数)。举个例子:

function closure(){
    let fronted=["js","css"];

    return function(){
        return fronted;
    }
}

let fronted = closure()(); <----运行两次,分别运行closure和返回的匿名函数

console.log(fronted);
fronted.push("html");
console.log(fronted);

我们在函数中声明一个数组并且初始化它,最后通过匿名函数(推荐使用匿名函数)返回。这样我们可以在函数外面获得内部的数组并且可以进行一些操作,如上运行结果如下:

Chrome浏览器是如何来识别一个闭包的

不同的浏览器对闭包也有不同的理解。下面笔者使用世界上最好的浏览器Chrome浏览器来演示下它是如何去识别一个闭包的,代码还是用的上面那个代码:

首先我们要打两个断点

第一步运行,并且请观察截图中红框框的地方

第二步运行,并且也请观察截图中红框框的地方,比较和上一步的不同

没错,多了一个“Closure”对象 并且指向了(closure)这个函数,说明到这里Chrome已经识别出了这是一个闭包。展开这个对象:

果然是世界上最好的浏览器,给我们展示了闭包中访问的变量。神器啊有木有...

闭包的原理

说了那么多,那么闭包的原理到底是什么呢?且听我慢慢道来。
看过我上一篇博客的朋友都知道,想访问一个变量那么必须要处在这个变量的作用域中。比如fronted这个变量在closure函数中定义,那么closure函数中的匿名函数就可以访问这个fronted变量。因为只能访问父域或者同域的变量。当匿名函数在自己内部访问了这个变量的时候就相当于持有了该变量的引用,所以当和这个匿名函数被 return 出去的时候,仍可以访问该变量。

闭包的能用来干什么

技术的出现时为了解决一类问题,闭包能用来干什么呢?

隐藏变量

通过闭包,我们可以向外界输出一个变量,不过并不是直接暴露出去而是通过类似于接口的函数向外暴露,这样既可以在外界访问这个变量又保证了这个变量不会被破坏。

模块化的始祖

据笔者所了解,JavaScript模块化就是借用闭包来实现的。通过定义一个module变量,并且向外暴露相关操作module的方法,来实现导入和导出。

使用闭包的注意点

通常来说,当一个函数运行结束后,函数中的变量内存会被回收掉,但是上一篇博客特地强调了闭包并不会这样。实际上如例子所示,即使closure函数运行完了,但是它返回的匿名函数中仍持有变量fronted的引用,因此这个变量会一直存在于内存中并且不会被回收(初非人为解除引用)。因此可以预见性得猜到,如果我们在程序中大量得使用闭包,那么大量的变量存在于内存中而占用前端内存资源会导致性能的下降。所以我们在开发过程用要慎用闭包。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96455.html

相关文章

  • JS核心作用域

    摘要:作用域链在执行上下文创建的时候,在变量对象之后创建作用域链,作用域链本身就包含变量对象,当函数被调用的时候,作用域链包含的是激活对象。我们可以用这个属性来假定作用域链的连接,它指的是链中的下一个对象。 什么是作用域 作用域是运行代码中某些特定部分的变量,函数和对象的可访问性及生命周期 javascript中的作用域 在javascript中有两种类型的作用域1.全局作用域2.局部作用域...

    Alan 评论0 收藏0
  • 将"回调地狱"按在地上摩擦的Promise

    摘要:回调地狱的问题在于写法过于繁琐不够优雅代码维护炒鸡蛋疼,所以一直被前端程序猿所诟病,尤其是维护类似代码的时候简直日了一群哈士奇。,对象状态以和为分水岭。方法返回一个带有拒绝原因参数的对象摘自对的解释。并且返回的也是一个对象。 这是一段旁白 异步虐我千百遍,我待异步如初恋!!做前端的同学做异步肯定都不陌生。因为JavaScript是单线程语言(也就是说不支持多线程编程,这不是废话么啊喂!...

    Yu_Huang 评论0 收藏0
  • javascript基础-Vue数据绑定前奏对象属性

    摘要:关于有人说我用删除这个属性不就好了之后打印发现它还是一只哈士奇。如下的解释如下操作符会从某个对象上移除指定属性。 javascript-Object-Property ? javascript-对象的属性的延伸学习 showImg(https://segmentfault.com/img/bVNH2S?w=640&h=640); 前言 在学习vue数据绑定的较底层原理时,被setter...

    zebrayoung 评论0 收藏0
  • JavaScript-面向对象、Object类型

    摘要:面向对象面向对象编程的全称为简称。面向对象编程是用抽象方式创建基于现实世界模型的一种编程方式。面向对象编程可以看做是使用一系列对象相互协作的软件设计。面向对象编程的三个主要特征是封装继承多态。 面向对象 面向对象编程的全称为Object Oriented Programming,简称OOP。面向对象编程是用抽象方式创建基于现实世界模型的一种编程方式。面向对象编程可以看做是使用一系列对象...

    amuqiao 评论0 收藏0
  • JavaScript深入闭包

    摘要:深入系列第八篇,介绍理论上的闭包和实践上的闭包,以及从作用域链的角度解析经典的闭包题。定义对闭包的定义为闭包是指那些能够访问自由变量的函数。 JavaScript深入系列第八篇,介绍理论上的闭包和实践上的闭包,以及从作用域链的角度解析经典的闭包题。 定义 MDN 对闭包的定义为: 闭包是指那些能够访问自由变量的函数。 那什么是自由变量呢? 自由变量是指在函数中使用的,但既不是函数参数也...

    caige 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<