昨天的文章中主要记录了,函数表达式与函数声明的区别

以及在JS中如何安全地使用递归

那么既然要深入地理解JS中的函数,闭包就是一个绕不开的概念

闭包

JS高编一书中对闭包的概念定义如下:

闭包是指有权访问另一个函数作用域中变量的函数

我们来理解这句话,闭包指的是一类函数

这类函数的特点是可以访问另一个函数的作用域

我们知道JS中Es6以下是没有块级作用域的

只有全局作用域,以及函数作用域

一般来讲,函数作用域里面的变量在函数外部是无法访问的

而闭包却可以访问另一个函数作用域,那么说明了什么?

说明闭包说白了就是在函数内部定义或声明的函数

以下面的代码举例

function createComparisonFunction(propertyName){// 用于创建比较函数的函数
return function(object1,object2){// 根据propertyName来比较对象的对应属性的值
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if(value1>value2){
return 1;
}else if(value1<value2){
return -1;
}else{
return 0;
}
}
}

这就是闭包的使用场景之一

我们在内部的函数中访问了外部函数的变量

而当内部匿名函数作为值返回后我们在函数的外部也能访问到函数createComparisonFunction内部的值

这样的结果似乎跟我们之前对JS的认知产生了冲突

我们知道当一个函数执行完毕后,其执行上下文便会被销毁

为其分配的内存也会被垃圾收集器回收

那么为什么闭包依旧可以访问呢?

之前我们讲过JS中的垃圾回收机制

当一个对象不再被引用时才会被垃圾收集器释放内存

而JS中的执行上下文,在ES5被称为活动对象,ES6中似乎被称为变量环境

不管名字是什么,其实就是指的一个保存变量声明等相关信息的对象

虽然 createComparisonFunction 已经执行完毕,但是由于其内部的匿名函数仍旧保存着对这个对象的引用,所以该对象无法被回收

这也是闭包占用内存多的原因

那么闭包的引用的这个对象什么时候会被回收呢?

var compareName = createComparisonFunction('name');
// compareName 保存了对返回的匿名函数的引用 // 一些操作 compareName = null;// 解除对返回的比较函数的引用

也就是当这个闭包不再被引用,闭包的执行上下文,与其外部函数的执行上下文都将一起被回收

闭包与变量

闭包虽然可以访问外部函数的值

但是其作用不是万能的,因为闭包引用的是外部函数的执行上下文

所以闭包只能获得闭包执行时的外部函数执行上下文中变量的最后一个值

function createFunctions(){
var result = new Array();
for (var i=0;i<10;i++){
result.push(function(){return i;})
}
return result;
}

在浏览器中运行结果如下

按照我们上面的结果来看,肯定是不符合我们的预期的

我们或许希望,array 数组中每个对象都返回对应执行时的值

那么我们可以通过JS中的参数传递都是值传递来完成这一点

将之前的函数改写为

function createFunctions(){
var result = new Array();
for (var i=0;i<10;i++){
result.push((function(num){
return function(){return num;}
})(i));
}
return result;
}

使用自执行函数来将每次循环的i值保存到不同的执行上下文中

我们来看看结果

这种方法相当于就是创建了十个执行上下文,每个返回的闭包都引用不同上下文,来实现的

所以十分耗费内存,在实践中不推荐使用

关于this对象

要注意的是,虽然闭包可以访问外部函数的执行上下文

但是并不意味着闭包可以直接访问外部函数的 this 和 arguments对象

因为每个函数在创建时都会自动地取得这两个变量,而不会去获取外部的this

所以如果希望在闭包中访问外部函数的this变量,那么需要在外部函数中创建一个变量来保存 this

内存泄漏

我们知道js的内存是由JS自己回收的

所以我们在获得便利的同时,也增加了内存泄漏的风险

因为这是我们不能控制的

我们只能尽量避免这种情况的发生

而跟闭包有关的主要是在DOM事件中,这里就先不展开讲了,感兴趣的小伙伴可以留言,给我说不定可以开个番外篇

Javascript高级编程学习笔记(24)—— 函数表达式(2)闭包的更多相关文章

  1. Javascript高级编程学习笔记(25)—— 函数表达式(3)模仿块级作用域

    昨天写了闭包 今天就来聊聊块级作用域的事情 在绝大多数编程语言中,都有块级作用域这个概念 什么是块级作用域呢? 前面我们在刚开始讲的时候说过,JS中的大括号(不在赋值运算符的后面)表示代码块 块级作用 ...

  2. Javascript高级编程学习笔记(23)—— 函数表达式(1)递归

    前面的文章中,我在介绍JS中引用类型的时候提过,JS中函数有两种定义方式 第一种是声明函数,即使用function关键字来声明 第二种就是使用函数表达式,将函数以表达式的形式赋值给一个变量,这个变量就 ...

  3. Javascript高级编程学习笔记(26)—— 函数表达式(4)私有变量

    私有变量 严格来讲,JS中没有私有成员的概念,所有对象属性都是公有的. 但是JS中有私有变量的概念 所有在函数中定义的变量都可以认为是私有变量,因为不能在函数外部进行访问 私有变量包括 1.函数参数 ...

  4. 《JavaScript高级程序设计》笔记:函数表达式(七)

    递归 function factorial(num){ if(num<=1){ return 1; }else { return num * arguments.callee(num-1); } ...

  5. Javascript高级编程学习笔记(16)—— 引用类型(5) Function类型

    JS中许多有趣的地方都和函数脱不了联系 那么是什么让JS中的函数这么有趣呢? 我们一起来看看吧 Function类型 在JS中函数实际上就是对象,每个函数都是Function类型的实例,和JS的其他引 ...

  6. Javascript高级编程学习笔记(7)—— 函数

    前几天有事耽搁了,今天继续更新 今天的主要内容是JS中的函数 这一篇主要讲函数的定义等内容,至于变量提升.执行环境.闭包.内存回收等内容在后面讲,高玩们可以不用看下面的正文了. 函数 首先来讲,函数对 ...

  7. JavaScript高级编程学习笔记(第三章之一)

    继续记笔记,JavaScript越来越有意思了. 继续... 第三章:JavaScript基础 ECMAScript语法在很大程度上借鉴了C和其它类似于C的语言,比如Java和Perl. 大小写敏感: ...

  8. Javascript高级编程学习笔记(6)—— 流程控制语句

    话不多说,我们直接开始进入今天的主题 流程控制语句 首先什么是流程控制语句呢? 顾名思义,就是控制流程的语句. 在JS中语句定义了ECMAScript中的主要语法,让我们可以使用一系列的关键字来完成指 ...

  9. Javascript高级编程学习笔记(3)—— JS中的数据类型(1)

    前一段时间由于事情比较多,所以笔记耽搁了一段时间,从这一篇开始我会尽快写完这个系列. 文章中有什么不足之处,还望各位大佬指出. JS中的数据类型 上一篇中我写了有关JS引入的Script标签相关的东西 ...

随机推荐

  1. Python MD5算法使用

    ## md5算法简介 1.  **简介**   MD5消息摘要算法(MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值 ...

  2. asp.net WebService如何去掉asmx后缀

    现在有一个发布好的WebService,地址是http://hovertree.com:2706/UploadExpenseToConstract.asmx能不能把最后面的asmx去掉呢?变成http ...

  3. 51ak带你看MYSQL5.7源码4:实现SQL黑名单功能

    博客迁移至: https://www.dboop.com/ 从事DBA工作多年 MYSQL源码也是头一次接触 尝试记录下自己看MYSQL5.7源码的历程 申明:个人Python编程很溜,但是C++还停 ...

  4. JS 变量提升与函数提升

    JS 变量提升与函数提升 JS变量提升 变量提升是指:使用var声明变量时,JS会将变量提升到所处作用域的顶部.举个简单的例子: 示例1 console.log(foo); // undefined ...

  5. PHP常用180函数总结【初学者必看】

    数学函数 1.abs(): 求绝对值 <span style="font-size: 14px;">$abs = abs(-4.2); //4.2<br>& ...

  6. 实验十四 第九组 张燕~杨蓉庆~杨玲 Swing图形界面组件

    实验十四  Swing图形界面组件 8-11-29 理论知识 Swing和MVC设计模式 (1)设计模式(Design pattern)是设计者一种流行的 思考设计问题的方法,是一套被反复使用,多数人 ...

  7. CPDA-战略管理

    战略管理-PEST分析-市场分析-竞争环境分析-SWOT分析-内/外部因素评价矩阵-国际化/多元化战略 战略管理: 战略分析->战略制定->战略实施->战略评价->战略分析,四 ...

  8. 第四次Scrum编码冲刺!!!!

    一.总体任务: 本次冲刺是完成对图书馆管理系统的最后三个功能的实现------管理员对用户授权.用户注销和用户查询 二.个人任务及完成情况:    本人本次的任务是实现对管理员对用户授权部分的界面与部 ...

  9. 第三次scrum作业

    一.第三次冲刺任务 ! 在已有的基础上实现图书馆管理员对图书信息的查询以及对图书借阅情况的查询. 二.用户故事 本次的用户是图书馆的管理员 用户输入对应的管理员的账号和密码 用户选择图书查询,进入图书 ...

  10. Python从入门到精通之Fifth!

    字典  类名:dict   字典是无序的. 字典的创建  info = {"k1":{1:"abc",[1,2,3]},"k2":True} ...