JS基础学习——闭包
JS基础学习——闭包
什么是闭包
闭包的定义如下,它的意思是闭包使得函数可以记住和访问它的词法范围,即使函数是在它声明的词法范围外执行。更简单来讲,函数为了自己能够正确执行,它对自己的词法范围产生闭包,在它执行完毕释放之前,它会阻止相关的词法范围提早关闭释放。
Closure is when a function is able to remember and access its lexical scope even when that function is executing outside its lexical scope.
一个比较简单的例子就是嵌套查询,如code 1所示,因为bar函数需要访问foo函数内的变量a,因此bar对foo的内部范围产生了闭包,但在这个例子中bar函数是在其声明时的词法范围内执行的,因此闭包现象不能很好体现,但是需要知道在这种嵌套函数中闭包也是存在的。
/*-----------code 1----------*/
function foo() {
var a = 2;
function bar() {
console.log( a ); // 2
}
bar();
}
foo();
code 2中闭包现象比较明显,按照函数作用域的理解,函数内部的变量在函数运行结束之后就应该消亡,但由于bar对foo的内部范围产生了闭包,使得bar在foo执行完毕之后还能继续访问foo的内部变量,具体来说,由于bar有对foo内部变量存在引用,因此在bar作为返回值被传递出去时对foo产生了闭包,这使得foo内部的变量继续存在,bar在词法范围外部执行时也能根据自己定义时的词法范围成功找到了a变量。需要注意,由于闭包占用内存空间,所以要谨慎使用闭包。尽量在使用完闭包后,及时解除引用,以便更早释放内存,如code 2中最后一句所示。
/*-----------code 2----------*/
function foo() {
var a = 2;
function bar() {
console.log( a );
}
return bar;
}
var baz = foo();
baz(); // 2 -- Whoa, closure was just observed, man.
baz = null;
循环闭包中的经典例子
code 3设计之初是希望arr中存放的2个方法的运行结果分别是0和1,但是由于两个function都对同一个变量i具有闭包,而变量i在循环的过程中发生了改变,因此最终运行结果不是希望的那样,两个方法都将返回2。
想要实现原先的设计目标,有两种方法可以实现,第一种是使用IIFE创建函数作用域,如code 4所示,第二种方法是使用let关键词,如code 5所示,let声明的循环变量绑定的是单次迭代作用域,每次迭代都会产生一个新的同名循环变量,具体看JS基础学习——作用域。
/*-----------code 3----------*/
function foo(){
var arr = [];
for(var i = 0; i < 2; i++){
arr[i] = function(){
return i;
}
}
return arr;
}
var bar = foo();
console.log(bar[0]());//2
/*-----------code 4----------*/
function foo(){
var arr = [];
for(var i = 0; i < 2; i++){
arr[i] = (function fn(j){
return function test(){
return j;
}
})(i);
}
return arr;
}
var bar = foo();
console.log(bar[0]());//0
/*-----------code 5----------*/
function foo(){
var arr = [];
for(let i = 0; i < 2; i++){
arr[i] = function(){
return i;
}
}
return arr;
}
var bar = foo();
console.log(bar[0]());//0
模块中的闭包
一个函数,它以对象为返回值,且对象中至少包含一个属性为内部函数,且该内部函数访问函数的私有变量(蕴含闭包),那么这个函数就是一个模块,有点类似于c++、java中的类概念。code 6就是一个模块函数。
/*-----------code 6----------*/
var foo = (function CoolModule() {
var something = "cool";
var another = [1, 2, 3];
function doSomething() {
console.log( something );
}
function doAnother() {
console.log( another.join( " ! " ) );
}
return {
doSomething: doSomething,
doAnother: doAnother
};
})();
foo.doSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3
参考资料:
[1] You don't know js -- Scope & Closures
[2] 深入理解闭包系列第四篇——常见的一个循环和闭包的错误详解
JS基础学习——闭包的更多相关文章
- JS基础学习——对象
JS基础学习--对象 什么是对象 对象object是JS的一种基本数据类型,除此之外还包括的基本数据类型有string.number.boolean.null.undefined.与其他数据类型不同的 ...
- JS基础学习——作用域
JS基础学习--作用域 什么是作用域 变量的作用域就是变量能被访问到的代码范围,比如在下面的这个js代码中,变量a的作用域就是函数foo,因此在全局作用域内的console.log(a)语句不能访问到 ...
- JS 基础学习随想
2012年就已经接触过了js,给我的印象:这是一门谈不上复杂的语言.大概这就是所谓的学的越浅,用的越少,觉得自己会的东西好像得更多吧!开始做基础练习题的时候觉得好像都十分简单.可是后来在做到对象数组的 ...
- handlebars.js基础学习笔记
最近在帮学校做个课程网站,就有人推荐用jquery+ajax+handlebars做网站前端,刚接触发现挺高大上的,于是就把一些基础学习笔记记录下来啦. 1.引用文件: jquery.js文件下载:h ...
- JS基础学习1
1 JS 概述 一个完整的javascript实现是由以下3个不同部分组成的: (1) 核心(ECMAscript) (2) 文档对象模型(DOM) Document object ...
- 两万字Vue.js基础学习笔记
Vue.js学习笔记 目录 Vue.js学习笔记 ES6语法 1.不一样的变量声明:const和let 2.模板字符串 3.箭头函数(Arrow Functions) 4. 函数的参数默认值 5.Sp ...
- JS基础学习篇(一)
近来一直在学习js和jquery.刚刚进入前端工作还没有多久,虽然大学里学习的是编程自认为也学的还可以,但前端接触的不多,一直认为前端十分简单.其实不然,特别是工作的时候要自己设计一个完整的项目前端, ...
- Node.js基础学习四之注册功能
前言:在Node.js学习(二)和(三)中介绍了如何在Node.js 中获取登录的用户名和密码与数据库进行验证并返回数据给客户端 需求:实现注册功能 为了区分登录和注册是两个不同的请求,在端口后面加上 ...
- JS基础学习(二)
昨天把网站上的基础知识看完了,下面是剩下的部分 第六节 JS Window浏览器对象模型 JavaScript全局对象,函数,变量均自动成为window对象的成员. 1.Window对象 1.获取浏览 ...
随机推荐
- (STM32F4) 精準的Delay不透過Timer
從一個厲害的國外工程師看來的delay寫法,使用while loop會使用幾個指令去計算,可能會需要多少時間. while(variable--); 這行代碼執行一次預估會消耗MCU 4 clock ...
- 三个常用的PHP图表类库
Jpgraph 只要把example中的require_once路径改了就放进来用吧,我下的是最新版的jpgraph-3.5.0b1,反正测试嘛,我记得跟3.0.7还是有差别的,把文件名都重新命名过了 ...
- LeetCode231.2的幂
231.2的幂 描述 给定一个整数,编写一个函数来判断它是否是 2 的幂次方. 示例 示例 1: 输入: 1 输出: true 解释: 2^0 = 1 示例 2: 输入: 16 输出: true 解释 ...
- oracle数据库导入dmp文件
最近在自己的机子上安装了oracle11g,今天把项目的测试数据库给导入进来了,方便在本地跑起来调试.下面记录一下过程: 1,导出测试数据库的文件; 这个是在公司三楼的一台机子上,用plsql中的工具 ...
- bzoj1221软件开发 费用流
题目传送门 思路: 网络流拆点有的是“过程拆点”,有的是“状态拆点”,这道题应该就属于状态拆点. 每个点分需要用的,用完的. 对于需要用的,这些毛巾来自新买的和用过的毛巾进行消毒的,流向终点. 对于用 ...
- bzoj3098 Hash Killer II 生日共计
题目传送门 题目大意: 让你构造一个字符串,使字符串在题目给出的哈希条件下统计出错. 思路:生日攻击,结论题,尚未理解. #include<bits/stdc++.h> #define C ...
- highcharts去掉x轴,y轴,轴线以及刻度
var chart = null; $.getJSON('https://data.jianshukeji.com/jsonp?filename=json/usdeur.json&callba ...
- 2019.3.13 final与static
final 当使用final修饰类的时候,表示类不能被继承(就是extends后面不能再加它了) final 注意事项: 当使用final修饰时,该方法不能被子类重写 当一个方法被标记为private ...
- 微信小程序图片上传放大预览删除代码
效果: 一,下面是上传图片的效果 image.js代码: Page({ //选择相册或拍照 data: { imgs: [] }, //上传图片 chooseImg: function (e) { v ...
- 破解myBase试用到期
请保持你的myBase7是关闭的 1.找到myBase7的安装目录(myBase.exe的目录): 2.右键编辑打开myBase.ini: 3.找到 App.UserLic.FirstUseOn,并在 ...