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基础学习——闭包的更多相关文章

  1. JS基础学习——对象

    JS基础学习--对象 什么是对象 对象object是JS的一种基本数据类型,除此之外还包括的基本数据类型有string.number.boolean.null.undefined.与其他数据类型不同的 ...

  2. JS基础学习——作用域

    JS基础学习--作用域 什么是作用域 变量的作用域就是变量能被访问到的代码范围,比如在下面的这个js代码中,变量a的作用域就是函数foo,因此在全局作用域内的console.log(a)语句不能访问到 ...

  3. JS 基础学习随想

    2012年就已经接触过了js,给我的印象:这是一门谈不上复杂的语言.大概这就是所谓的学的越浅,用的越少,觉得自己会的东西好像得更多吧!开始做基础练习题的时候觉得好像都十分简单.可是后来在做到对象数组的 ...

  4. handlebars.js基础学习笔记

    最近在帮学校做个课程网站,就有人推荐用jquery+ajax+handlebars做网站前端,刚接触发现挺高大上的,于是就把一些基础学习笔记记录下来啦. 1.引用文件: jquery.js文件下载:h ...

  5. JS基础学习1

    1 JS 概述 一个完整的javascript实现是由以下3个不同部分组成的: (1)     核心(ECMAscript) (2)     文档对象模型(DOM)  Document object ...

  6. 两万字Vue.js基础学习笔记

    Vue.js学习笔记 目录 Vue.js学习笔记 ES6语法 1.不一样的变量声明:const和let 2.模板字符串 3.箭头函数(Arrow Functions) 4. 函数的参数默认值 5.Sp ...

  7. JS基础学习篇(一)

    近来一直在学习js和jquery.刚刚进入前端工作还没有多久,虽然大学里学习的是编程自认为也学的还可以,但前端接触的不多,一直认为前端十分简单.其实不然,特别是工作的时候要自己设计一个完整的项目前端, ...

  8. Node.js基础学习四之注册功能

    前言:在Node.js学习(二)和(三)中介绍了如何在Node.js 中获取登录的用户名和密码与数据库进行验证并返回数据给客户端 需求:实现注册功能 为了区分登录和注册是两个不同的请求,在端口后面加上 ...

  9. JS基础学习(二)

    昨天把网站上的基础知识看完了,下面是剩下的部分 第六节 JS Window浏览器对象模型 JavaScript全局对象,函数,变量均自动成为window对象的成员. 1.Window对象 1.获取浏览 ...

随机推荐

  1. 二、为什么要选用pytest以及 pytest与unittest比较

    为什么要选择pytest,我看中的如下: 写case,不需要像unittest那样,创建测试类,继承unittest.TestCase pytest中的fixture(类似于setUp.tearDow ...

  2. Linux下命令别名配置

    在~/.bashrc文件中添加相关命令别名内容,可以降低风险操作 1. vim ~/.bashrc alias rm='rm -i' alias cp='cp -i' alias mv='mv -i' ...

  3. JAVA数据结构--插入排序

    插入排序(英语:Insertion Sort)是一种简单直观的排序算法.它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入.插入排序在实现上,通常采用in- ...

  4. 使用Git向GitHub上上传代码

    参考:http://www.cnblogs.com/yxhblogs/p/6130995.html 如果遇到[git无法pull仓库refusing to merge unrelated histor ...

  5. 洛谷 P3182 [HAOI2016]放棋子(错排问题)

    题面 luogu 题解 裸的错排问题 错排问题 百度百科:\(n\)个有序的元素应有\(n!\)个不同的排列,如若一个排列使得所有的元素不在原来的位置上,则称这个排列为错排:有的叫重排.如,1 2的错 ...

  6. 格子刷油漆(dp)-----------蓝桥备战系列

    标题:格子刷油漆 X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如图1所示),现需要把这些格子刷上保护漆. 你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但 ...

  7. AtCoder Beginner Contest 113 B

    B - Palace Time limit : 2sec / Memory limit : 1024MB Score: 200 points Problem Statement A country d ...

  8. PHP操作Access数据库

    ADO是一项微软的技术,ADO指ActiveX数据对象(ActiveX Data Objects). 链接数据库 <?php header("Content-Type:text/htm ...

  9. B/S和C/S架构简单理解

    B/S和C/S架构简单理解 B/S结构.C/S结构 B(browser浏览器)-S(server服务器),说简单点就是通过浏览器来请求服务器,实现数据交互.那自然了,C(client客户端软件)-S( ...

  10. PIE SDK打开栅格数据

    1. 功能简介 GIS将地理空间数据表示为矢量数据和栅格数据.矢量数据模型使用点.线和多边形来表示具有清晰空间位置和边界的空间要素,如控制点.河流和宗地等,每个要素被赋予一个ID,以便与其属性相关联. ...