当前位置: 首页 > 编程日记 > 正文

Js----闭包

1、闭包的概念:(我找了很多,看大家的理解)

  A:闭包是指可以包含自由(未绑定到特定对象)变量的代码块;

           这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。

  B:当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。

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

      或简单理解为定义在一个函数内部的函数,内部函数持有外部函数内变量的引用。

  D:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

  E:闭包就是能够读取其他函数内部变量的函数。闭包可以简单理解成“定义在一个函数内部的函数“。

   在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

  F:如果一个函数访问了它的外部变量,那么它就是一个闭包。

     注意,外部函数不是必需的。通过访问外部变量,一个闭包可以维持(keep alive)这些变量。在内部函数和外部函数的例子中,

     外部函数可以创建局部变量,并且最终退出;但是,如果任何一个或多个内部函数在它退出后却没有退出,

     那么内部函数就维持了外部函数的局部数据。

  G:当内部函数 在定义它的作用域 的外部 被引用时,就创建了该内部函数的闭包 ,如果内部函数引用了位于外部函数的变量,

      当外部函数调用完毕后,这些变量在内存不会被 释放,因为闭包需要它们。

  H:一个持有外部环境变量的函数就是闭包

2、闭包的特性:

  封闭性:外界无法访问闭包内部的数据,如果在闭包内声明变量,外界是无法访问的,除非闭包主动向外界提供访问接口;

  持久性:一般的函数,调用完毕之后,系统自动注销函数,而对于闭包来说,在外部函数被调用之后,闭包结构依然保存在。

3、闭包的用途:

function f1(){var n = 123;function f2(){    //f2是一个闭包alert(n)}    return f2;}

A、读取函数内部的变量
  B、让这些变量的值始终保持在内存中。不会再f1调用后被自动清除。
  C、方便调用上下文的局部变量。利于代码封装。
  原因:f1是f2的父函数,f2被赋给了一个全局变量,f2始终存在内存中,f2的存在依赖f1,因此f1也始终存在内存中,不会在调用结束后,被垃圾回收机制回收。

4、闭包的理解:


function init() {var name = "Chrome";    //创建局部变量name和局部函数alertNamefunction alertName() {  //alertName()是函数内部方法,是一个闭包alert(name);        //使用了外部函数声明的变量,内部函数可以访问外部函数的变量}alertName();
}
init();//一个变量在源码中声明的位置作为它的作用域,同时嵌套的函数可以访问到其外层作用域中声明的变量function outFun(){var name = "Chrome";function alertName(){alert(name);}return alertName;   //alertName被外部函数作为返回值返回了,返回的是一个闭包
}var myFun = outFun();
myFun();
/*
闭包有函数+它的词法环境;词法环境指函数创建时可访问的所有变量。
myFun引用了一个闭包,闭包由alertName()和闭包创建时存在的“Chrome”字符串组成。
alertName()持有了name的引用,
myFunc持有了alertName()的的访问,
因此myFunc调用时,name还是处于可以访问的状态。*/function add(x){return function(y){return x + y;};
}var addFun1 = add(4);
var addFun2 = add(9);console.log(addFun1(2)); //6
console.log(addFun2(2));  //11
//add接受一个参数x,返回一个函数,它的参数是y,返回x+y
//add是一个函数工厂,传入一个参数,就可以创建一个参数和其他参数求值的函数。
//addFun1和addFun2都是闭包。他们使用相同的函数定义,但词法环境不同,addFun1中x是4,后者是5

5、闭包的应用场景:

  A:闭包应用场景之setTimeout

//原生的setTimeout传递的第一个函数不能带参数setTimeout(function(param){alert(param)},1000)//通过闭包可以实现传参效果function func(param){return function(){alert(param)}}var f1 = func(1);setTimeout(f1,1000);

B:闭包应用场景之回调

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title></title><link rel="stylesheet" href="">
</head>
<style>body{font-size: 12px;}h1{font-size: 1.5rem;}h2{font-size: 1.2rem;}
</style>
<body><p>哈哈哈哈哈哈</p><h1>hhhhhhhhh</h1><h2>qqqqqqqqq</h2><a href="#" id="size-12">12</a><a href="#" id="size-14">14</a><a href="#" id="size-16">16</a><script>function changeSize(size){return function(){document.body.style.fontSize = size + 'px';};}var size12 = changeSize(12);var size14 = changeSize(14);var size16 = changeSize(16);document.getElementById('size-12').onclick = size12;document.getElementById('size-14').onclick = size14;document.getElementById('size-16').onclick = size16;//我们定义行为,然后把它关联到某个用户事件上(点击或者按键)。我们的代码通常会作为一个回调(事件触发时调用的函数)绑定到事件上
</script>
</body>
</html>

  C:闭包应用场景之封装变量

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title>闭包模拟私有方法</title><link rel="stylesheet" href="">
</head>
<body>
<script>//用闭包定义能访问私有函数和私有变量的公有函数。var counter = (function(){var privateCounter = 0; //私有变量function change(val){privateCounter += val;}return {increment:function(){   //三个闭包共享一个词法环境
                change(1);},decrement:function(){change(-1);},value:function(){return privateCounter;}};})();console.log(counter.value());//0
    counter.increment();counter.increment();//2//共享的环境创建在一个匿名函数体内,立即执行。//环境中有一个局部变量一个局部函数,通过匿名函数返回的对象的三个公共函数访问。</script>
</body>
</html>

D:闭包应用场景之为节点循环绑定click事件

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title></title><link rel="stylesheet" href="">
</head>
<body><p id="info">123</p><p>E-mail: <input type="text" id="email" name="email"></p><p>Name: <input type="text" id="name" name="name"></p><p>Age: <input type="text" id="age" name="age"></p><script>function showContent(content){document.getElementById('info').innerHTML = content;};function setContent(){var infoArr = [{'id':'email','content':'your email address'},{'id':'name','content':'your name'},{'id':'age','content':'your age'}];for (var i = 0; i < infoArr.length; i++) {var item = infoArr[i];document.getElementById(item.id).onfocus = function(){showContent(item.content)}}}setContent()//循环中创建了三个闭包,他们使用了相同的词法环境item,item.content是变化的变量//当onfocus执行时,item.content才确定,此时循环已经结束,三个闭包共享的item已经指向数组最后一项。/*** 解决方法1     通过函数工厂,则函数为每一个回调都创建一个新的词法环境*/function showContent(content){document.getElementById('info').innerHTML = content;};function callBack(content){return function(){showContent(content)}};function setContent(){var infoArr = [{'id':'email','content':'your email address'},{'id':'name','content':'your name'},{'id':'age','content':'your age'}];for (var i = 0; i < infoArr.length; i++) {var item = infoArr[i];document.getElementById(item.id).onfocus = callBack(item.content)}}setContent()/*** 解决方法2        绑定事件放在立即执行函数中*/function showContent(content){document.getElementById('info').innerHTML = content;};function setContent(){var infoArr = [{'id':'email','content':'your email address'},{'id':'name','content':'your name'},{'id':'age','content':'your age'}];for (var i = 0; i < infoArr.length; i++) {(function(){var item = infoArr[i];document.getElementById(item.id).onfocus = function(){showContent(item.content)}})()//放立即执行函数,立即绑定,用每次的值绑定到事件上,而不是循环结束的值
        }}setContent()/*** 解决方案3        用ES6声明,避免声明提前,作用域只在当前块内*/function showContent(content){document.getElementById('info').innerHTML = content;};function setContent(){var infoArr = [{'id':'email','content':'your email address'},{'id':'name','content':'your name'},{'id':'age','content':'your age'}];for (var i = 0; i < infoArr.length; i++) {let item = infoArr[i];      //限制作用域只在当前块内
            document.getElementById(item.id).onfocus = function(){showContent(item.content)}}}setContent()
</script>
</body>
</html>

6、闭包的优缺点:

  缺点:

A:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,

       在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

      B:闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,

      把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,

                   不要随便改变父函数内部变量的值。

  优点:

      A:减少创建全局变量 减少传递给函数的参数量

      B:避免全局变量的污染

         C:私有成员的存在

      D:希望一个变量长期驻扎在内存当中

7、闭包对页面的影响:

  通过使用闭包,我们可以做很多事情。比如模拟面向对象的代码风格;更优雅、更简洁的表达出代码;

        在某些方面提升代码的执行效率。

 

转载于:https://www.cnblogs.com/liaohongwei/p/10560309.html

相关文章:

【C++】【四】企业链表

// 企业链表.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // 链表改进版 企业常用#include <iostream> #include<stdlib.h>//链表小节点 不包含数据域 typedef struct linknode {struct linknode* next; }linknode; //链表节点 数据指…

GoldenGate的Logdump工具使用简介

Logdump工具是GoldenGate提供的一个用于查询、分析、过滤、查看和保存存储在trail文件或extract文件中的数据的工具。1、启动Logdump工具[oraclerhel6 ~]$ cd /ogg [oraclerhel6 ogg]$ ./logdumpOracle GoldenGate Log File Dump Utility for Oracle Version 12.2.0.1.1 OGGCOR…

scala惰性函数

惰性计算&#xff08;尽可能延迟表达式求值&#xff09;是许多函数式编程语言的特性。惰性集合在需要时提供其元素&#xff0c;无需预先计算它们&#xff0c;这带来了一些好处。首先&#xff0c;您可以将耗时的计算推迟到绝对需要的时候。其次&#xff0c;您可以创造无限个集合…

计算机组成原理-第3章-3.1

|--总线&#xff1a;本质上就是一组连线&#xff0c;通路 |--发展过程&#xff1a; 分散连接时代&#xff1a; 运算器为中心 ↓ 存储器为中心 ↓ 中断&#xff0c;DMA的出现修正 ↓ 依旧无法解决效率问题 总线连接时代&#xff1a; 以CPU为核心&#xff0c;双总线&#xff1a;M…

【C++】【三】单向链表

// 单向链表.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 //#include <iostream> #include<stdlib.h>typedef struct LINKNODE {void* data;struct LINKNODE* next; }linknode;typedef struct LINKLIST {LINKNODE* head;int size; }lin…

gulp相关说明

1.当你按下ctrls 或切换到浏览器&#xff0c;浏览器将会会自动刷新 如果你修改的是html文件将会刷新网页如果你修改的是css或less&#xff0c;这个less文件或css文件将会被重载而不是刷新整个页面&#xff08;这个特性在写单页面应用时尤为实用&#xff09;2.模板引入 考虑以下…

IDEA中提示:Warning:java: 源值1.5已过时, 将在未来所有发行版中删除

问题描述&#xff1a; 运行Java Web项目时&#xff0c;IDEA中提示&#xff1a;Warning:java: 源值1.5已过时, 将在未来所有发行版中删除解决方法&#xff1a; 1. 打开【File】—【Project Structure】&#xff0c;找到以下两个地方&#xff1a; Project Structure->Proje…

mysql 数据库乱码

mysql 数据库乱码 转载自https://www.cnblogs.com/gne-hwz/p/8748028.html 如有侵权&#xff0c;请联系。 遇到这种情况&#xff0c;现有项目的数据库已经建好&#xff0c;数据表也已经创建完成。 问题来的&#xff0c;数据库不能插入中文&#xff0c;调试时候发现中文数据从发…

【C++】【二】动态数组-Dynamic_linklist

// dynamicArray.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <stdlib.h> #include <iostream>typedef struct DYNAMICARRAY {int* paddr;int size;int capacity; }dynamiCarray;dynamiCarray* Init_dynamiCarray() {dynam…

在MySQL和PostgreSQL之外,为什么阿里要研发HybridDB数据库?

编者按\\在大数据火遍IT界之前&#xff0c;大家对数据信息的挖掘通常聚焦在BI&#xff08;Business Intelligence&#xff09;之上。BI具有着明确的分析需求&#xff0c;清晰地知道需要处理哪些信息&#xff0c;并且如何最终获得多维度的SQL类型数据&#xff0c;这种多维度的分…

Linux命令-安装zip和unzip命令

1 [rootiz2zeea05by6vofxzsoxdbz elasticsearch]# unzip elasticsearch-6.2.4.zip 2 -bash: unzip: command not found 如果你如法使用unzip命令解压.zip文件&#xff0c;可能是你没有安装unzip软件&#xff0c;下面是安装方法 命令&#xff1a; yum list | grep zip/unzip …

【C++】【五】循环链表

数据结构&#xff1a;具体的高效有序的管理内存的方法。 链表&#xff1a;数据结构的一种 节点&#xff1a;每一块内存 每一个节点可以是裸指针 也可以是结构体 &#xff0c;结合企业链表的思路可以将类型强转&#xff0c;完成高效的访问。main.cc // 单向循环链表.cpp …

IntelliJ IDEA 设置项目编码

2019独角兽企业重金招聘Python工程师标准>>> IntelliJ IDEA-> Editor->File Encodings 转载于:https://my.oschina.net/bigxuan/blog/804345

util.sh 脚本

#!/bin/bash for i in zzzhadoop101 zzzhadoop102 zzzhadoop103 doecho " $i "ssh $i /opt/module/jdk1.8.0_144/bin/jps donebin目录是在环境变量里的&#xff0c;所以在哪都可以执行 /home/zzz/bin目录下touch util.sh [zzzhadoop101 bin]$ touch …

bzoj3467: Crash和陶陶的游戏

就一篇题解&#xff1a; BZOJ3467 : Crash和陶陶的游戏 - weixin_34248487的博客 - CSDN博客 1.离线&#xff0c;建出Atrie树&#xff1b;B树的倍增哈希数组&#xff0c;节点按照到根路径字典序排序 2.处理A节点对应前缀对应B中的极长可以匹配的区间。在父亲节点区间内二分即可…

载入图像并且显示

#include <opencv2/opencv.hpp> using namespace cv;void main( ) { const char *fileName "1.jpg";Mat srcImage imread("1.jpg");imshow(fileName,srcImage);waitKey(0); }

alter system switch logfile与alter system archive log current的区别

以前知道 ALTER SYSTEM SWITCH LOGFILE对单实例数据库或RAC中的当前实例执行日志切换&#xff0c; ALTER SYSTEM ARCHIVE LOG CURRENT会对数据库中的所有实例执行日志切换&#xff0c; 所以在RAC环境上大多时间一般使用后者&#xff0c;而今天遇到了不管执行多少次ALTER SYSTEM…

【C++】【六】约瑟夫问题

核心代码&#xff1a; int index 1;clinknode* pcur list->head.next;while (Size_circlelinkist(list)>1){if (index N) {mynum* temnum (mynum*)pcur;printf("%d ", temnum->val);clinknode* pnext pcur->next;RemoveByValue_circlelinkist(list…

第六章:内核数据结构

6.1链表链表表示一种存放和操作的可变数据元素的数据结构。链表与静态数组不同的是它包含的元素是动态创建并且插入链表的&#xff0c;在编译时不必知道具体需要多少个元素。另外链表中每个元素的创建时间各不相同&#xff0c;所以它们在内存中无需占用连续的空间。链表中每个元…

【C++】【七】栈的实现

栈的线性表实现 stack_liner_stack.h #ifndef STACK_LINER_H #define STACK_LINER_H #include <stdlib.h> #define MAX_SIZE 1024 #define stack_liner_false 0 #define stack_liner_true 1typedef struct STACK_LINER_H {void* data[MAX_SIZE];int size; }stack_liner…

推荐两款简单好用的图片放大jquery插件

一、zoomfiy.js 推荐可以从这里下载 使用说明&#xff1a; 使用该jquery 插件引入该插件的js:zoomfiy.js 或 min引入该插件的css:zoomfiy.css 或 min前后顺序都可js里加入 调用插件的函数 $(这里写要放大的图片).zoomify();如果有ajax 新生成的图片&#xff0c;要在ajax里再次调…

对图像的缩放与旋转

#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" int main( ) {// 读取图像cv::Mat srcImage cv::imread("..\\images\\flower3.jpg");// 图像读取是否成功if( !srcImage.data ) return 1; // 对图像的缩放与旋…

工具库 --- Validator (JS正则)

工具库 --- Validator 今天写的是一个正则验证类 单例模式 工具库地址&#xff1a;github.com/WeForStudy/… npm地址&#xff1a;www.npmjs.com/package/slm… 单例模式 减少不必要的对象生存&#xff0c;减少资源的占用 由于只需要new一次&#xff0c;项目中其他项目共用一个…

【C++】【九】栈的应用

【C】【九】栈的应用 就近匹配原理及其步骤&#xff1a; 中缀转后缀&#xff1a;

linux中错误日志等级

info&#xff1a;仅是一些基本的讯息说明而已&#xff1b;notice&#xff1a;比 info 还需要被注意到的一些信息内容&#xff1b;warning 或 warn&#xff1a;警示讯息&#xff0c;可能有问题&#xff0c;但是还不至于影响到某个 daemon 作。err 或 error &#xff1a;一些重大…

Mat类简略结构

class CV_EXPORTS Mat { public&#xff1a;int flags; // 标志位 int dims ; // 数组的维数int rows,cols; uchar *data ; // 指向数据的指针int * refcount ; // 指针的引用计数器 阵列指向用户分配的数据时&#xff0c;当指针为 NULL };

数据结构之快速排序

首先快速排序&#xff1a;就是选择一个基数&#xff0c;然后从两端依次进行比较&#xff0c;若右边大于基数&#xff0c;则不进行交换&#xff0c;直到右边的数据小于基数&#xff0c;然后冲左边开始和基数比较&#xff0c;若左边的小于基数&#xff0c;则进行下一个比较&#…

【C++】【十】二叉树

树的基本概念&#xff1a; 树具有递归性&#xff0c;非线性 完全二叉树 &#xff1a;所有节点都在 举例&#xff1a; 递归遍历二叉树&#xff1a; #include <stdlib.h> #include <stdio.h> #include <iostream> #include<string.h>typedef struct B…

记一次网络共享打印机故障

刚开始去到办公室发现电脑之间的环境是XP跟WIN10查看共享主机发现没有监听139和445端口 然后在网卡属性把Microsoft网络客户端和Microsoft网络的文件和打印机共享删除重启 重新安装这两个客户端 发现虽然共享主机有监听端口 但是其他主机还是不能访问 最后检查发现主机之间的工…