博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
闭包那一点事
阅读量:6923 次
发布时间:2019-06-27

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

hot3.png

闭包要解决的问题

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

闭包的基本模式

在函数内部创建函数(内部函数),在这个内部函数中,可以操作外部函数中的变量

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();  //1b();  //not defined   (只能在局部使用,类似闭包)
var a = function b(){  	console.log(1);  	console.log(b); }();		// 1  function b(){...}

 

 

 

转载于:https://my.oschina.net/u/2949632/blog/803795

你可能感兴趣的文章
Notes on the Dirichlet Distribution and Dirichlet Process
查看>>
SharePoint 2013 内容部署报错
查看>>
EF中修改对象的值的问题。。。(字段超级多的时候)
查看>>
HT for Web基础动画介绍
查看>>
win8.1 64位环境建设android开发环境
查看>>
unity, UGUI Text fadeIn
查看>>
网盘搜索
查看>>
LeetCode——Palindrome Linked List
查看>>
Access-Control-Allow-Origin与跨域
查看>>
MyBatis 入门到精通(三) 高级结果映射
查看>>
[原创]渗透测试工具
查看>>
Word 打包 zip 并提供下载
查看>>
SQL SERVER中什么情况会导致索引查找变成索引扫描
查看>>
C语言easy忽视的细节(第四部分)
查看>>
介绍一个好用的软件--多个WIN远程连接
查看>>
【Xamarin 开发 IOS --IOS ViewController生命周期】
查看>>
Best Time to Buy and Sell Stock I,II,III [leetcode]
查看>>
android 之 下载管理器 无论监测在当地的设计思路
查看>>
浅谈python web框架中的orm设计
查看>>
IntelliJ IDEA于Make Project时报:子字符串不是票面金额的结束、非法的表达式显示启动...
查看>>