Js中闭包的概念、原理、作用及应用菜鸟教程_闭包小白基础

一、闭包概念闭包:有权访问另一个函数作用域中的变量的函数,一般情况就是在一个函数中包含另一个函数。从官方定义我们知道闭包是一个函数,只不过这个函数有[超能力],可以访问到另一个函数的作用域。为什么说这个叫做[超能力]呢?因为我们知道函数作用域是独立的、封闭的,外部的执行环境是访问不了的,但是闭包具有这个能力和权限。那闭包是怎样的一个表现形式呢?第一,闭包是一

Js中闭包的概念、原理、作用及应用菜鸟教程

一、闭包概念
闭包:有权访问另一个函数作用域中的变量的函数,一般情况就是在一个函数中包含另一个函数。
从官方定义我们知道闭包是一个函数,只不过这个函数有[超能力],可以访问到另一个函数的作用域。
为什么说这个叫做[超能力]呢?
因为我们知道函数作用域是独立的、封闭的,外部的执行环境是访问不了的,但是闭包具有这个能力和权限。
那闭包是怎样的一个表现形式呢?
第一,闭包是一个函数,而且存在于另一个函数当中
第二,闭包可以访问到父级函数的变量,且该变量不会销毁

Js中闭包的概念、原理、作用及应用菜鸟教程_闭包小白基础

function person(){
    var name = '有鱼';
    function cat(){
        console.log(name);
    }
    return cat;
}
var per = person();// per的值就是return后的结果,即cat函数
per();// 有鱼 per()就相当于cat()
per();// 有鱼 同上,而且变量name没有销毁,一直存在内存中,供函数cat调用
per();// 有鱼

二、闭包原理
闭包的实现原理,其实是利用了作用域链的特性,我们都知道作用域链就是在当前执行环境下访问某个变量时,如果不存在就一直向外层寻找,最终寻找到最外层也就是全局作用域,这样就形成了一个链条。
例如:

var age = 18;
function cat(){
    age++;
    console.log(age);// cat函数内输出age,该作用域没有,则向外层寻找,结果找到了,输出[19];
}
cat();//19

看到这里,大家都会说这不就是最简单的函数和变量形式吗?闭包在哪里?别急,我们接着往下看:
如果我们再次调用时,结果会一直增加,也就变量age的值一直递增。

cat();//20
cat();//21
cat();//22

如果程序还有其他函数,也需要用到age的值,则会受到影响,而且全局变量还容易被人修改,比较不安全,这就是全局变量容易污染的原因,所以我们必须解决变量污染问题,那就是把变量封装到函数内,让它成为局部变量。

function person(){
    var age = 18;
    function cat(){
        age++;
        console.log(age);
    }
    return cat;
}
person();// 19
person();// 19

这里又出现问题了,每次调用函数person,进入该作用域,变量age就会重新赋值为18,所以cat的值一直是19;所以需要做一下调整:

var per = person();//per相当于函数cat
per();// 19 即cat() 这样每次调用不在经过age的初始值,这样就可以一直增加了
per();// 20
per();// 21

而且变量age在函数内部,不易修改和外泄,相对来说比较安全。

Js中闭包的概念、原理、作用及应用菜鸟教程_闭包小白基础

三、闭包作用
作用1:隐藏变量,避免全局污染
作用2:可以读取函数内部的变量
同时闭包使用不当,优点就变成了缺点:
缺点1:导致变量不会被垃圾回收机制回收,造成内存消耗
缺点2:不恰当的使用闭包可能会造成内存泄漏的问题
这里简单说一下,为什么使用闭包时变量不会被垃圾回收机制收销毁呢,这里需要了解一下JS垃圾回收机制;
JS规定在一个函数作用域内,程序执行完以后变量就会被销毁,这样可节省内存;使用闭包时,按照作用域链的特点,闭包(函数)外面的变量不会被销毁,因为函数会一直被调用,所以一直存在,如果闭包使用过多会造成内存销毁。

四、闭包应用
需求:实现变量a 自增
1、通过全局变量,可以实现,但会污染其他程序

var a = 10;
function Add(){
    a++;
    console.log(a);
}
Add();
Add();
Add();

 2、定义一个局部变量,不污染全局,但是实现不了递增

var a = 10;
function Add2(){
    var a = 10;
    a++;
    console.log(a);
}
Add2();
Add2();
Add2();
console.log(a);

3、通过闭包,可以是函数内部局部变量递增,不会影响全部变量,完美!!

var a  = 10;
function Add3(){
    var a = 10;
    return function(){
        a++;
        return a;
    };
};
var cc =  Add3();
console.log(cc());
console.log(cc());
console.log(cc());
console.log(a);

 

海计划公众号
(0)
上一篇 2020/03/20 07:33
下一篇 2020/03/20 07:32

您可能感兴趣的内容

  • sandal菜鸟教程_Sass 的基础库

    sandal菜鸟教程 官方网址:http://marvin1023.github.io/sandal/ GitHub:https://github.com/marvin1023/s…

    2020/03/06
  • 无编译/无服务器,实现浏览器的 CommonJS 模块化入门知识_模块基础知识入门

    引言平时经常会逛 Github,除了一些 star 极高的大项目外,还会在 Github 上发现很多有意思的小项目。项目或是想法很有趣,或是有不错的技术点,读起来都让人有所收获。所以准备汇总成一个「漫游Github」系列,不定期分享与解读在 Github 上偶遇的有趣项目。本系列重在原理性讲解,而不会深扣源码细节。好了下面进入正题。本期要介绍的仓库叫 one

    2020/03/22
  • codelf攻略教程_变量命名神器

    codelf攻略教程 官方网址:https://unbug.github.io/codelf/ GitHub:https://github.com/unbug/codelf 简介描…

    2020/03/06
  • 前端网络监控与断网重链入门攻略_网络基础教程

    业务背景最近在做大屏数据可视化项目得时候,在思考项目交付和运行情况得时候,考虑到了需要在公司大屏显示器上面展示,突然想到了项目可能面临断网及其网速慢得情况下得一下展示问题,因此作为专栏进行这两个问题得讲解问题一 WebSocket 在网络终端和重新联网后自动链接**知识点: ** 理解WebSocket心跳及重连机制在使用websocket的过程中,有时候会

    2020/03/20
  • 在Node.js 12 中使用 ESM基础知识_node使用攻略

    Node.js 12 之后开始支持 ECMAScript Modules(简称ESM),不过并不是默认开启或者自动切换。坦率地说我也卡了一阵子才搞清楚怎么直接使用。简单记一下吧。首先,Node.js 12 里默认支持的仍是 CommonJS,如果直接按照 ESM 写,然后跑,会报错,错误信息里有个关键字:/cjs/loader.js,只要你看到它,可以肯定是

    2020/03/22
  • Scene.js基础入门_一个基于 JavaScript 时间轴的动画库

    Scene.js基础入门 官方网址:http://daybrush.com/scenejs/ GitHub:https://github.com/daybrush/scenejs …

    2020/03/07
  • Effeckt.css基础指南_一个高性能的过渡和动画库

    Effeckt.css基础指南 官方网址:https://h5bp.org/Effeckt.css/ GitHub:https://github.com/h5bp/Effeckt….

    2020/03/06
  • javascript如何实现异步请求?基础教程_异步入门基础教程

    JS中通常实现浏览器和服务器的数据交互,那么异步操作是关键的一部分:通常情况下,浏览器想服务器发送请求,服务器相应请求返回数据,浏览器执行异步操作。使用定时函数模拟异步请求数据:// 使用定时函数模拟异步请求:
    // 方法一:使用回调函数
    function doSomething(callback){setTimeout(function(){console

    2020/03/22
  • javascript字符串进行编码的方法:escape编码、encodeURI编码、encodeURIComponent编码基础入门_字符串入门基础

    1.escape();
    语法:
    escape(string) // string 必需。要被转义或编码的字符串。
    返回值:
    已编码的 string 的副本。其中某些字符被替换成了十六进制的转义序列。
    说明:
    该方法不会对 ASCII 字母和数字进行编码,也不会对下面这些 ASCII 标点符号进行编码:** * @ – _ + . / **
    解码:
    un

    2020/04/06
  • php类 属性和方法的关系小白入门_php使用指南

    一 . 属性关系1 . public属性:在类的外部和内部都可以调用 被继承能够重构2 . protected属性:在类的内部可以调用外部不能可以被继承并且重构3 . private属性:只有在类的内部调用 不能被继承4 . static属性:类的内部和外部都能调用 内部调用方法(self::属性变量) 外部调用方法(类名::属性变量) 二 .

    2020/03/30
  • vue.js 过渡和动画小白攻略_过渡基础入门

    Vue 在插入、更新或者移除 DOM 时,动态添加css类名来达到想要的动画效果1.transition标签给元素包裹一个transition标签,并设置name属性的值,这个值可以随意设置,但是他会决定Dom更新时自动添加的css类名这里name=”xxx”作为演示<button @click="isShow = !isShow

    2020/03/24
  • 微信小程序跳转小程序新手入门_小程序指南教程

    以前小程序跳小程序直接通过api调用跳转即可,但在2018.11.1下午微信公众平台通知需做navigateToMiniProgramAppIdList配置,否则无法提交审核,配置要跳转的微信小程序id ,最多不能超过10个。每个小程序可跳转的其他小程序数量限制为不超过10个,而且跳转appid必须在配置列表中,负责回调 fail appId “${appI

    2020/03/24
  • js禁止页面滚动小白基础_滚动攻略教程

    开发移动端页面的时候有一个很比较常见的需求,在出现弹窗时,禁止滑动弹窗后面的主体页面。如何实现呢,往下看js实现整个页面禁止滚动:document.body.addEventListener(‘touchmove‘, function(e){e.preventDefault();}, { passive: false }); //passive 参数不能省

    2020/03/31
  • websocket.io基础入门_socket使用攻略

    一. 服务器端使用express服务const path = require(‘path’);
    const app =express();//其实是一个监听函数
    const server = require(‘http’).createServer(app);
    //使用静态文件中间件,把当前目录下面的public目录作为静态文件的根目录
    app.use(ex

    2020/03/29
  • Vue 改变数据,页面不刷新的问题指南攻略_刷新基础知识教程

    最近在用 element-ui 开发一个网站,使用 table 组件时,发现修改完数据,有时候会延迟一两秒,页面才会发生变化。看了一下代码,发现修改数据的代码是这样的// popupData是修改的数据,修改完后,赋值给对应的表格数据
    this.tableData[this.currentRow] = this.popupData注意事项(以下内容摘自官方文

    2020/03/30
  • FEX菜鸟指南百度Web前端研发部出品

    FEX基础入门 官方网址:http://fex.baidu.com/ 简介描述:百度Web前端研发部出品

    2020/03/05