Javascript高级编程学习笔记(24)—— 函数表达式(2)闭包
昨天的文章中主要记录了,函数表达式与函数声明的区别
以及在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)闭包的更多相关文章
- Javascript高级编程学习笔记(25)—— 函数表达式(3)模仿块级作用域
		
昨天写了闭包 今天就来聊聊块级作用域的事情 在绝大多数编程语言中,都有块级作用域这个概念 什么是块级作用域呢? 前面我们在刚开始讲的时候说过,JS中的大括号(不在赋值运算符的后面)表示代码块 块级作用 ...
 - Javascript高级编程学习笔记(23)——  函数表达式(1)递归
		
前面的文章中,我在介绍JS中引用类型的时候提过,JS中函数有两种定义方式 第一种是声明函数,即使用function关键字来声明 第二种就是使用函数表达式,将函数以表达式的形式赋值给一个变量,这个变量就 ...
 - Javascript高级编程学习笔记(26)—— 函数表达式(4)私有变量
		
私有变量 严格来讲,JS中没有私有成员的概念,所有对象属性都是公有的. 但是JS中有私有变量的概念 所有在函数中定义的变量都可以认为是私有变量,因为不能在函数外部进行访问 私有变量包括 1.函数参数 ...
 - 《JavaScript高级程序设计》笔记:函数表达式(七)
		
递归 function factorial(num){ if(num<=1){ return 1; }else { return num * arguments.callee(num-1); } ...
 - Javascript高级编程学习笔记(16)—— 引用类型(5) Function类型
		
JS中许多有趣的地方都和函数脱不了联系 那么是什么让JS中的函数这么有趣呢? 我们一起来看看吧 Function类型 在JS中函数实际上就是对象,每个函数都是Function类型的实例,和JS的其他引 ...
 - Javascript高级编程学习笔记(7)——  函数
		
前几天有事耽搁了,今天继续更新 今天的主要内容是JS中的函数 这一篇主要讲函数的定义等内容,至于变量提升.执行环境.闭包.内存回收等内容在后面讲,高玩们可以不用看下面的正文了. 函数 首先来讲,函数对 ...
 - JavaScript高级编程学习笔记(第三章之一)
		
继续记笔记,JavaScript越来越有意思了. 继续... 第三章:JavaScript基础 ECMAScript语法在很大程度上借鉴了C和其它类似于C的语言,比如Java和Perl. 大小写敏感: ...
 - Javascript高级编程学习笔记(6)——   流程控制语句
		
话不多说,我们直接开始进入今天的主题 流程控制语句 首先什么是流程控制语句呢? 顾名思义,就是控制流程的语句. 在JS中语句定义了ECMAScript中的主要语法,让我们可以使用一系列的关键字来完成指 ...
 - Javascript高级编程学习笔记(3)—— JS中的数据类型(1)
		
前一段时间由于事情比较多,所以笔记耽搁了一段时间,从这一篇开始我会尽快写完这个系列. 文章中有什么不足之处,还望各位大佬指出. JS中的数据类型 上一篇中我写了有关JS引入的Script标签相关的东西 ...
 
随机推荐
- django admin的实用配置
			
https://www.cnblogs.com/wumingxiaoyao/p/6928297.html
 - Mysql必知必会 第一章 了解SQL
			
第一章 了解SQL 1.1 数据库基础 1.1.1 什么是数据库 数据库的定义:保存有组织的数据的容器 数据库软件不是数据库,而是DBMS 1.1.2 表 表(Table)的定义:某种特定类型数据的结 ...
 - 教程:使用cPanel管理域名和数据库
			
cPanel是一个基于web的基于web的控制面板,它简化了许多常见的系统管理任务,如网站创建.数据库部署和管理等.本指南向您展示了如何使用cPanel用户帐户管理域和数据库.所有这些指令都与位于端口 ...
 - my new blog
			
博客迁移至: https://www.dboop.com/
 - Django学习笔记(进阶篇)
			
Django学习笔记(进阶篇):http://www.cnblogs.com/wupeiqi/articles/5246483.html
 - Python+Selenium 利用ID,XPath,tag name,link text,partial link text,class name,css,name定位元素
			
使用firefox浏览器,查看页面元素,我们以“百度网页”为示例 一.ID定位元素 利用find_element_by_id()方法来定位网页元素对象 ①.定位百度首页,输入框的元素 ②.编写示 ...
 - 异步async与await的简单探究
			
在学习.net core的过程中,到处见到异步的使用,Task.async.await随处可见.有点疑惑,就去了解了下这个过程是怎样的. 下面是一段代码,去看看是怎么执行的吧. 一.看看异步执行的方式 ...
 - python将文本转化成语音并播放
			
一.问题 在学习的过程中,我们会涉及到将文本信息,转化成语音的过程,比如:我爬取了一个小说的网站,我要将里面的内容进行语音处理.目前能够进行语音的方法还是很多,比如win32com,百度ai. 二.解 ...
 - django学习,session与cookie
			
Cookies,某些网站为了辨别用户身份.进行session跟踪而储存在用户本地终端上的数据(通常经过加密).Cookie最早是网景公司的前雇员Lou Montulli在1993年3月的发明.Cook ...
 - docker部署pinpoint
			
pinpoint-collector部署 Dockerfile FROM tomcat8:jdk8 MAINTAINER limugen<limugen@uce.cn> ENV APP_H ...