什么是闭包:

有权访问另一个函数作用域的变量的函数

简单的说,Javascript允许使用内部函数—即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。

闭包是嵌套的内部函数
闭包存在于嵌套的内部函数中

闭包的主要作用:

1.可以读取函数内部的变量
2.让这些变量的值始终保持在内存中,变量或参数不会被垃圾回收机制回收GC

产生闭包的条件:

函数嵌套
内部函数引用了外部函数的数据(变量/函数)

闭包的优点:

变量长期驻扎在内存中
避免全局变量的污染

闭包的缺点:

常驻内存会增大内存的使用量
使用不当会造成内存泄露
闭包会在父函数外部,改变父函数内部变量的值

闭包使用详解:

当想要的得到f1函数的局部变量时,正常情况下,这是办不到的,只有通过变通方法才能实现。那就是在函数的内部,再定义一个函数

function f1() {var n = 999;function f2() {console.log(n); // 999}
}

上面代码中,函数f2就在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是 JavaScript 语言特有的”链式作用域”结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。既然f2可以读取f1的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

function f1() {var n = 999;function f2() {console.log(n);}return f2;
}
var result = f1();
result(); // 999

上面代码中,函数f1的返回值就是函数f2,由于f2可以读取f1的内部变量,所以就可以在外部获得f1的内部变量了。闭包就是函数f2,即能够读取其他函数内部变量的函数。由于在 JavaScript 语言中,只有函数内部的子函数才能读取内部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

闭包的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中

请看下面的例子,闭包使得内部变量记住上一次调用时的运算结果。

 function zxxs(zxx) {return function () {return zxx++;};}var inc = zxxs(5);inc() // 5inc() // 6inc() // 7

上面代码中,zxx是函数zxxs的内部变量。通过闭包,zxx的状态被保留了,每一次调用都是在上一次调用的基础上进行计算。从中可以看到,闭包inc使得函数zxxs的内部环境,一直存在。所以,闭包可以看作是函数内部作用域的一个接口。为什么会这样呢?原因就在于inc始终在内存中,而inc的存在依赖于zxxs,因此也始终在内存中,不会在调用结束后,被垃圾回收机制回收。

闭包的另一个用处,是封装对象的私有属性和私有方法:

  function Person (name) {var agefunction setAge (n) {age = n}function getAge () {return age}return {name: name,getAge: getAge,setAge: setAge}}var p1 = Person('zxx')p1.setAge(18)p1.getAge() // 18

上面代码中,函数Person的内部变量age,通过闭包getAge和setAge,变成了返回对象p1的私有变量。

注意,外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。

函数执行完后,函数内的局部变量没有释放,占用内存时间会变长,容易造成内存泄漏(内存被占用,但是没有用上)

function fn1 () {var arr = new Array[1000]function fn2 () {console.log(arr.length)}return fn2
}
var f = fn1() // 已经产生闭包
f()f = null // 让内部函数成为垃圾对象-->回收闭包

习题1

var name = 'The Window'
var object = {name: 'My Object',getNameFunc: function () {return function () {return this.name}}
}
alert(object.getNameFunc()())  //The Window
object.getNameFunc() // 执行完变成一个函数,this指向window
var name = 'The Window'
var object = {name: 'My Object',getNameFunc: function () {var that = thisreturn function () {return that.name}}
}
alert(object.getNameFunc()())  // My Object

习题2

function outerFun(){var a=0;function innerFun() {a++;alert(a);}return innerFun;
}
var obj = outerFun();
obj();  // 结果为1
obj();  // 结果为2
var obj2 = outerFun();
obj2();  // 结果为1
obj2();  // 结果为2

习题3

function foo (x) {var tmp = 3function bar (y) {console.log(x + y + (++tmp))}bar(10)
}
foo(2) // 16
foo(2) // 16
foo(2) // 16
foo(2) // 16

这里只是函数调用,不是闭包

function foo (x) {var tmp = 3return function (y) {console.log(x + y + (++tmp))}
}
var bar = foo(2)
bar(10) // 16
bar(10) // 17
bar(10) // 18
bar(10) // 19

当你return的是内部function时,就是一个闭包。
一个函数访问了它的外部变量,那么它就是一个闭包

一道经典的闭包面试题

  function fun(n,o){console.log(o);return {fun:function(m){return fun(m,n);}}}var a = fun(0); // undefineda.fun(1); // 0a.fun(2); // 0a.fun(3); // 0var b=fun(0).fun(1).fun(2).fun(3); //undefined,0,1,2var c=fun(0).fun(1); //undefined,0c.fun(2); // 1c.fun(3); // 1

详解:

转换为等价代码
return返回的对象的fun属性对应一个新建的函数对象,
这个函数对象将形成一个闭包作用域,
使其能够访问外层函数的变量n及外层函数fun

为了不将fun函数和fun属性搞混,我们将上述代码修改如下:

function _fun_(n,o){console.log(o);return {fun:function(m){return _fun_(m,n);}}
}

var a = fun(0); // undefined 产生了闭包 n = 0
a.fun(1); // 0 产生了闭包,但是由于没有绑定变量,闭包马上就消失了, 始终用的是a里面的闭包
a.fun(2); // 0 产生了闭包,但是由于没有绑定变量,闭包马上就消失了, 始终用的是a里面的闭包
a.fun(3); // 0 产生了闭包,但是由于没有绑定变量,闭包马上就消失了, 始终用的是a里面的闭包
var b = fun(0).fun(1).fun(2).fun(3); // undefined,0,1,2 会不断产生新的闭包
等价代码
var b1 = b.fun(1);
var b2 = b1.fun(2);
var b3 = b2.fun(3);
var c = fun(0).fun(1); // undefined,0,
c.fun(2); // 1 当前c的闭包是 1
c.fun(3); // 1 当前c的闭包是 1
虽然c.fun(2)和c.fun(3)都产生了新的闭包,但是由于没有赋给新的变量,闭包接着就消失了

详解JavaScript的闭包相关推荐

  1. window 程序报错 自动重启_好程序员web前端教程之详解JavaScript严格模式

    好程序员web前端教程之详解JavaScript严格模式,严格模式(Strict mode)是由ECMA-262规范定义的新兴JavaScript标准,发布于2009年12月第五版.旨在改善错误检查功 ...

  2. 详解 javascript中offsetleft属性的用法(转)

    详解 javascript中offsetleft属性的用法 转载  2015-11-11   投稿:mrr    我要评论 本章节通过代码实例介绍一下offsetleft属性的用法,需要的朋友可以做一 ...

  3. 详解JavaScript变量类型判断及domReady原理 写得很好

    原文:详解JavaScript变量类型判断及domReady原理 我们知道,在开发JavaScript时候,经常要判断JavaScript变量类型,此 JavaScript教程 详细介绍JS变量的判断 ...

  4. 详解JavaScript数组过滤相同元素的5种方法

    详解JavaScript数组过滤相同元素的5种方法:https://www.jb51.net/article/114490.htm 转载于:https://www.cnblogs.com/bydzha ...

  5. es6字符串添加html标签,JavaScript_详解JavaScript ES6中的模板字符串,在 ES6 中引入了一种新的字符 - phpStudy...

    详解JavaScript ES6中的模板字符串 在 ES6 中引入了一种新的字符串字面量 - 模板字符串,除了使用反引号 (`) 表示,它们看上去和普通的字符串没有什么区别.在最简单的情况下,他们就是 ...

  6. js模板字符串自定义类名_详解JavaScript ES6中的模板字符串

    这篇文章主要介绍了详解JavaScript ES6中的模板字符串,JS的ES6版本带来诸多简洁化方面的重大改进,需要的朋友可以参考下 在 ES6 中引入了一种新的字符串字面量 - 模板字符串,除了使用 ...

  7. 详解JavaScript对象深拷贝

    详解JavaScript对象深拷贝 在几乎所有编程语言中,对象都以引用形式保存给变量.复制给其他变量.JavaScript语言也是如此.因此简单的进行赋值操作进行复制仅仅是对对象数据的引用地址进行一个 ...

  8. 详解Javascript本地存储的方式、区别及应用场景

    详解Javascript本地存储的方式.区别及应用场景 一.方式 javaScript本地缓存的方法我们主要讲述以下四种: cookie sessionStorage localStorage ind ...

  9. 详解 JavaScript 的 IIFE 语法

    详解 JavaScript 的 IIFE 语法 IIFE 语法 IIFE 语法的一些变体 小括号去哪儿了? 命名的 IIFE 防止连接文件时出现问题 使用箭头函数代替函数表达式 一些不推荐的立即调用函 ...

  10. javascript 本地对象和内置对象_详解 JavaScript 面向对象

    1. 概述 JavaScript面向对象比较难理解的点是类的继承.不管是es5写法还是es6写法,JavaScript继承的本质是原型链.具体可看我的上一篇文章: 田浩:详解原型.原型链.构造函.实例 ...

最新文章

  1. chinese-typesetting:更好的中文文案排版
  2. Linux使用parted进行分区及拓展实验
  3. sqlplus 中@ ? !号的作用
  4. left join、right join、inner join的区别
  5. 谜题39:您好,再见!
  6. 为iPhone 12上市做准备,台积电月底前投产A14 Bionic芯片
  7. POJ_1753解答过程的理解
  8. 光伏发电系统最大功率点跟踪MPPT matlab/simulink仿真 扰动观察法
  9. XRD测试常见问题及解答(三)
  10. 七夕将至,20行js代码给女友做个卡通P图微信机器人
  11. 深度学习-fashion_mnist预测
  12. 数据库 流量切分_ABTEST平行流量切分和分层流量切分高效实现及优缺点分析
  13. .net 2.0安装包打不开_Android——bilibili缓存视频合并教程[2.0]
  14. java本地缓存简介
  15. static(静态变量,方法)
  16. 华为鸿蒙系统有望搭载手机上吗,华为智选车载智慧屏将12月上市:有望搭载鸿蒙系统...
  17. 多多视频带货最容易出单的4个品类!
  18. 计算机内存智能清理系统好些,电脑清理软件哪个好用且占用内存小你知道吗
  19. web调用IC卡读卡器开发第三章--高频卡读卡号
  20. pandas导出excel表格时报错:ValueError: No engine for filetype: ‘‘

热门文章

  1. 明天发布一个基于Silverlight的类Visio小型绘图工具项目。
  2. 各国股市开盘与收盘时间
  3. 高效管理 Android 前台服务
  4. 做底层 AI 框架和做上层 AI 应用,哪个对自己的学术水平(或综合能力)促进更大?...
  5. 4.软件架构设计:大型网站技术架构与业务架构融合之道 --- 操作系统
  6. 3.Jenkins 权威指南 --- 设置构建作业
  7. 8.TCP/IP 详解卷1 --- Traceroute 程序
  8. 62. 拆分初始化负载
  9. 36. In Depth Magento System Configuration
  10. 16. Shell scripts