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标签相关的东西 ...
随机推荐
- CentOS7下开放端口
memcached等服务启动后,外网默认是无法访问的,因为防火墙不允许,所以要开启防火墙,让其可以访问这些端口号. 方法一:使用firewall 1.运行命令:firewall-cmd --get-a ...
- vue调试方法
vue调试方法有如下三种 1.chrome谷歌插件vue-devtools 2.console.log().console.error().alert().debugger 3.设置全局变量,分为两种 ...
- python抓取网页数据处理后可视化
抓取文章的链接,访问量保存到本地 #coding=utf-8 import requests as req import re import urllib from bs4 import Beauti ...
- CentOS7 安装VNC
系统环境:CentOS Linux release 7.6.1810Kernel:3.10.0-957.el7.x86_64系统现状:最小化安装,没有安装任何图形支持软件 安装图形化支持 不建议安装G ...
- Mysql运行状态查询命令及调优详解
(转载自点击打开链接) MySQL运行状态及调优(一) 一.查看MySQL运行情况SHOW STATUS; 二.查看INNODB数据库引擎运行状态SHOW ENGINE INNODB STATUS; ...
- 探索未知种族之osg类生物---渲染遍历之认识SceneView
前言 我们在进行osg程序的开发时,最常用到的场景管理方式是“场景节点树”的结构, a 场景树底端的叶节点(osg::Geode)包含了各种需要渲染的几何体的顶点和渲染状态信息: b ...
- Spring @Value取值为null或@Autowired注入失败
@Value 用于注入.properties文件中定义的内容 @Autowired 用于装配bean 用法都很简单,很直接,但是稍不注意就会出错.下面就来说说我遇到的问题. 前两天在项目中遇到了一个问 ...
- vue项目中跳转到外部链接方法
当我们在文件中,如果是vue页面中的内部跳转,可以用this.$router.push()实现,但是如果我们还用这种方法跳到外部链接,就会报错,我们一看链接的路径,原来是我们的外部链接前面加上了htt ...
- spring Resource(转)
http://blog.csdn.net/u011225629/article/details/47143075
- 数据库镜像转移Failover Partner
数据库主体镜像转换:任务 - 镜像 - 故障转移 sqlserver2008 数据库镜像服务配置完成后,大家会发现我们有了两个数据库服务,这两个服务可以实现自动故障转移,那么我们的程序如何实现自动连接 ...