文档章节

闭包那一点事

SubinY
 SubinY
发布于 2016/12/10 22:33
字数 1683
阅读 13
收藏 1
点赞 0
评论 0

闭包要解决的问题

提供一种间接的方式能够访问到函数内部的数据(变量)

贴吧上一个闭包有什么用的问题和回答

闭包的基本模式

在函数内部创建函数(内部函数),在这个内部函数中,可以操作外部函数中的变量
01 在函数(外部)中创建函数(内部函数),在该函数(内部函数)中操作外部函数中的变量
02 在外部函数中,把内部函数作为返回值返回
03 调用外部函数,并接收其返回值(是一个函数)
04 调用接收到的返回值(内部函数),来间接的操作外部函数中的变量

关注点1(为什么直接返回num不算是标准闭包?)

  function inner(){
    var num = 10;
    return num;
  };
  var fn1 = inner();
  var fn2 = inner();
  console.log(fn1);  //10
  console.log(fn2);  //10

其实每一个函数体就是一个闭包,但该博文所指的闭包并没有这么简单。这里的inner尽管也能从外部读取inner函数的局部变量,但fn1,fn2是通过各开辟一个内存空间去存储num的值,就相当于fn1=new Number(10),fn2 = new Number(10),这样不能修改inner里面的变量值,并不能达到获取内部变量和修改内部变量,其次我们想要得到的是将inner内部的变量暴露出外部使用,这明显fn1,fn2各玩各的。

闭包的完整认识关系

需求:想要在函外面(另外一个函数中)访问某一个函数内部的局部变量
闭包:在函数内部使用函数
闭包链式作用域:一个子对象可以沿着他的父对象访问父对象的所有变量,反之,则不行

function  sum() {
        var a = 10;
        function  showMessage() {

            //根据链式作用域在这个函数内部可以访问变量a
            alert(a);
        }

        return showMessage;

    }

    //调用sum
 var showMes =  sum();//调用完成后,正常情况局部变量应该被销毁,但最终没有
 showMes();

    //通过上面的使用,局部变量a没有销毁
    //闭包的作用:1.延长局部变量的生命周期
    //如果有很多局部变量,那么延长他们的生命周期,会大量占用内存,慎重使用

闭包获取内部数据及修改内部数据

一、获取单个数据(考虑赋值)

    function func() {
        var num = 123;
        return function (a) {
            if (a !== undefined)  //容错操作
            {
                num = a;
            }
                return num;
        }
    }

    var f1 = func();
    var x = f1(456);   //通过参数修改内部变量
    var y = f1();
    console.log(x);    //456
    console.log(y);    //123

二、获取多个数据两种方式(返回数组或对象)

    function func() {
        var name = "张学友";
        var age = 40;
        return [
                function getName() {
                    return name;
                },
                function getAge() {
                    return age;
                }
        ]
    }

    var foo = func();
    console.log(foo[0]());      //张学友
    console.log(foo[1]());      //40

说明:上面的代码能够满足返回多个变量值的需求,但是要数组操作的方式并不常见,且和使用习惯不符合。

利用对象返回并设置对个变量值

function foo() {
        var name = "张学友";
        var age = 45;

        return {
            getName:function () {
                return name;
            },
            getAge:function () {
                return age;
            },
            setName:function (nameValue) {
                name = nameValue;
            },
            setAge:function (ageValue) {
                age = ageValue;
            }
        }
    }

    var func = foo();
    console.log(func.getName());        //张学友
    console.log(func.getAge());         //45

    func.setName("张三");
    func.setAge(30);
    console.log(func.getName());        //张三
    console.log(func.getAge());         //30

 

尽量少用全局变量和闭包

一、在函数中使用var操作符定义一个变量,那么当这个函数执行完毕之后,这个变量也会被销毁(也有的情况下不会,比如闭包,后面会说明),而全局变量会一直存在。所以在我们写代码时,尽量少的使用全局变量,滥用全局变量,简直就是一个会令人恶心的习惯,因为它会带来很多不必要的麻烦。

  • 1:变量过多,命名麻烦
  • 2:局部变量,忘记使用var定义,修改了全局变量,这样的错误对于代码的维护简直是噩梦
  • 3:全局变量会在页面卸载前一直存在,损耗不必要的内存。

有两个网址都是第一个解释作用域和闭包,第二个解释闭包,作用域链,和垃圾回收机制

***************************************************************************

在说闭包常用场景时前先知道javascript的线程任务优先级,对下面理解有很大帮助

进程和线程:

进程指的是系统中正在运行的一个应用程序。
线程:一个进程中可以有一个或多个线程,线程是CPU调度的最小单位,是真正执行任务的。
多线程:一个中可能有多条线程,多条线程之间并发的执行多个不同的任务。
单线程:一个进程中只有一条线程,即同一时间只能执行一个操作,只能干一件事情。

javascript是单线程的:

js中的线程主要处理三块任务:(由上到下优先级处理)
01 渲染任务
02 js的代码执行任务
03 js中的事件处理任务(如setTimeOut方法)

 

那么来了究竟闭包常用什么地方呢

以下闭包常用场景

1、DOM操作

//函数定义和调用一起使用,
    //形式:(function sum(){})(),简化成(函数的定义)(函数的调用);
    var btns = document.getElementsByTagName('button');
    //遍历按钮
    for(var i= 0;i < btns.length;i++){
//        btns[i].onclick = (function (a) {
//            alert(a);
//        })(i)
        (function (a) {
         btns[a].onclick = function () {
                alert(a);
            }

     })(i) ;
    }


    当点击按钮的时候,需要输出i值,那么这个函数首先回会去寻找自己函数内部有没有对应的i值,如果有就直接访问这个i值,如果没有就要沿着闭包链式作用域去他的父对象中寻找对应变量i, 所以会去for循环中寻找i值,但是注意函数执行实在按钮点击的时候才触发,按钮点击是一个延迟操作,当按钮点击的时候for中的i值执行已经完毕,而且值是循环长度,所以我们获取的值5;(注释部分)
    通过闭包每一次循环都会保存i值,在弹出i值所在的函数中放置一个变量,那么就可以实现输出0-4;

*************************************************************************************************

2、定时器中闭包的使用

for(var i = 0; i < 4; ++i){
    // (function(a){
    //   setInterval(function(){
    //     console.log(a);
    //   },0)
    // })(i)
    setInterval((function (a) {
            console.log(a)
        })(i),0);

  }

注释部分是出现无序的数字,并且定时器没有停止,反之第二种写法可以获得想要效果

其他:函数名函数只能函数体内调用:

var a = function b(){
      console.log(1);
};

a();  //1
b();  //not defined   (只能在局部使用,类似闭包)
var a = function b(){
  	console.log(1);
  	console.log(b); 
}();		// 1  function b(){...}

 

 

 

© 著作权归作者所有

共有 人打赏支持
SubinY
粉丝 8
博文 86
码字总数 63828
作品 0
佛山
程序员
可能引发编程革命的 4 门语言

所有人都听说过“应该学好 C”,“Java 是 Web 开发者的首选”等等,它们几乎成为了真理。那么问题来了,难道就没有其他语言能挤走这些老家伙,使他们不再受欢迎?还是说十年后我们还是依靠着...

oschina ⋅ 2014/10/31 ⋅ 78

干货分享:让你分分钟学会 javascript 闭包

闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它。因此,本文不会对闭包的概念进行大篇...

snowing1990 ⋅ 2016/03/30 ⋅ 0

强烈反对粘虫似的软件依赖项安装模式!!!!!!!!!!

现在有一些软件,其实用户只需要那那个软件的功能,至于什么安装啊纯属一个过程,完全不是用户需要做的。现在的一些软件,在安装的地方莫名其妙的搞出一大堆依赖项,而且还需要用户去下载,去...

clonne ⋅ 2012/06/28 ⋅ 10

大佬饭局马云再缺席!别瞎猜,我只是有点小骄傲

大家好,我叫马云。对,就是那个后悔创立阿里,不喜欢钱,一个月赚一二十个亿很难受的那个马云。这几天正在参加互联网大会,丁磊请客我没去。于是就有人各种推理分析,还头头是道的。其实真的...

有态度的互联网人 ⋅ 2017/12/04 ⋅ 0

勇士斗恶龙:没那么复杂的Js闭包(改)

本文之前发表过一次,虽然当时也是精心书写过,但还是感觉有些问题本说明白,又走上了"把简单的事说复杂"的老毛病,所以第二次修改希望让看的人,尤其是对于闭包还心有畏惧的TX能有些收获. 内部函...

顽Shi ⋅ 2014/01/10 ⋅ 1

RxSwift之路 1#Swift语法知识准备

在开始学习 RxSwift 之前,一定要对 Swift 相关语法有所了解,否则就很难理解为什么可以这样。关于 Swift 的学习其实只要看看 Swift 的官方文档就可够了。我之前也列过一些学习资源:来自一线...

没故事的卓同学 ⋅ 2017/07/11 ⋅ 0

前端计划——一道经典的JavaScript问题(含闭包、事件轮询、作用域等概念解释)

前言:这是一道很经典的Js面试题,涉及到闭包、变量作用域、setTimeout等知识,对于深入理解这些内容很有帮助 题目描述 题目解释 首先,为了下面解释这道题,我们先来补充一些预备知识(大神...

Alarak ⋅ 2017/01/04 ⋅ 0

理解并解决IE的内存泄漏方式[翻译2]

大家节日快乐!俺就继续这个IE内存泄漏的主题来作为节日礼物了,并且相当欢迎大家来一起讨论。这一节讲Closures引起的内存泄漏,最后我还是决定把Closures翻译成了闭包或闭包函数。而且又在K...

唐玄奘 ⋅ 2017/12/12 ⋅ 0

请问sem_init的返回值

请问sem_init的返回值到底是多少,为什么我的调用后返回值为128。谢谢。请问哪里有linux API的详细使用说明,包括linux的POSIX API,我刚搞LINUX开发没多久,感觉找资料特费劲。VC开发,直接看...

徐志强 ⋅ 2011/03/11 ⋅ 1

深入理解javascript系列(九):应用闭包

理论是自信的基础,结合理论的实践才能让我们走的更远。 前两个系列,我记录了闭包的学习,如何利用闭包解决实际问题了?其实,很多东西你我都知道,不是一蹴而就的,不是你今天学了就会了,...

Panthon ⋅ 06/13 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Spring Boot整合模板引擎thymeleaf

项目结构 引入依赖pom.xml <!-- 引入 thymeleaf 模板依赖 --><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId......

yysue ⋅ 15分钟前 ⋅ 0

ConstraintLayout使用解析

AndroidStudio3.0创建Project默认的布局就是ConstraintLayout。 AndroidStudio3.0前的可以自己修改,使用ConstraintLayout。 为了要使用ConstraintLayout,我们需要在app/build.gradle文件中...

_OUTMAN_ ⋅ 26分钟前 ⋅ 0

OSChina 周三乱弹 —— 这样的女人私生活太混乱了

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @ 胖达panda :你经历过体验到人生的大起大落吗?我一朋友在10秒内体验了,哈哈。@小小编辑 请点一首《almost lover》送给他。 《almost love...

小小编辑 ⋅ 今天 ⋅ 9

自己动手写一个单链表

文章有不当之处,欢迎指正,如果喜欢微信阅读,你也可以关注我的微信公众号:好好学java,获取优质学习资源。 一、概述 单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对...

公众号_好好学java ⋅ 今天 ⋅ 0

Centos7重置Mysql 8.0.1 root 密码

问题产生背景: 安装完 最新版的 mysql8.0.1后忘记了密码,向重置root密码;找了网上好多资料都不尽相同,根据自己的问题总结如下: 第一步:修改配置文件免密码登录mysql vim /etc/my.cnf 1...

豆花饭烧土豆 ⋅ 今天 ⋅ 0

熊掌号收录比例对于网站原创数据排名的影响[图]

从去年下半年开始,我在写博客了,因为我觉得业余写写博客也还是很不错的,但是从2017年下半年开始,百度已经推出了原创保护功能和熊掌号平台,为此,我也提交了不少以前的老数据,而这些历史...

原创小博客 ⋅ 今天 ⋅ 0

LVM讲解、磁盘故障小案例

LVM LVM就是动态卷管理,可以将多个硬盘和硬盘分区做成一个逻辑卷,并把这个逻辑卷作为一个整体来统一管理,动态对分区进行扩缩空间大小,安全快捷方便管理。 1.新建分区,更改类型为8e 即L...

蛋黄Yolks ⋅ 今天 ⋅ 0

Hadoop Yarn调度器的选择和使用

一、引言 Yarn在Hadoop的生态系统中担任了资源管理和任务调度的角色。在讨论其构造器之前先简单了解一下Yarn的架构。 上图是Yarn的基本架构,其中ResourceManager是整个架构的核心组件,它负...

p柯西 ⋅ 今天 ⋅ 0

uWSGI + Django @ Ubuntu

创建 Django App Project 创建后, 可以看到路径下有一个wsgi.py的问题 uWSGI运行 直接命令行运行 利用如下命令, 可直接访问 uwsgi --http :8080 --wsgi-file dj/wsgi.py 配置文件 & 运行 [u...

袁祾 ⋅ 今天 ⋅ 0

JVM堆的理解

在JVM中,我们经常提到的就是堆了,堆确实很重要,其实,除了堆之外,还有几个重要的模块,看下图: 大 多数情况下,我们并不需要关心JVM的底层,但是如果了解它的话,对于我们系统调优是非常...

不羁之后 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部