网站首页 > 教程文章 正文
什么是闭包?
百度百科定义:闭包就是能够读取其他函数内部变量的函数。创建闭包的通常方式,是在一个函数内部创建另一个函数
最常见的闭包结构如下
function aaa(){
var name = "xxx"
return function bbb(){
alert(name);
}
}
如上代码,bbb函数内可以访问aaa函数作用域内的变量
闭包解决了什么问题?
1. 可以读取函数内部的变量;
2. 让这些变量的值始终保持在内存中。不会在函数调用后被清除;
闭包的定义及其优缺点
闭包 是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量
闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。
闭包是javascript语言的一大特点,主要应用闭包场合主要是为了:设计私有的方法和变量。
一般函数执行完毕后,局部活动对象就被销毁,内存中仅仅保存全局作用域。但闭包的情况不同!
avascript的垃圾回收原理
(1)、在javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收;
(2)、如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。
使用闭包的好处
那么使用闭包有什么好处呢?使用闭包的好处是:
1.希望一个变量长期驻扎在内存中
2.避免全局变量的污染
3.私有成员的存在
全局变量
函数可以访问由函数内部定义的变量,如:
function myFunction() {
var a = 4;
return a * a;
}
函数也可以访问函数外部定义的变量,如:
var a = 4;
function myFunction() {
return a * a;
}
计数器困境
设想下如果你想统计一些数值,且该计数器在所有函数中都是可用的。
你可以使用全局变量,函数设置计数器递增:
var counter = 0;
function add() {
return counter += 1;
}
add();
add();
add();
// 计数器现在为 3
但问题来了,页面上的任何脚本都能改变计数器,即便没有调用 add() 函数。
如果我在函数内声明计数器,如果没有调用函数将无法修改计数器的值:
function add() {
var counter = 0;
return counter += 1;
}
add();
add();
add();
// 本意是想输出 3, 但事与愿违,输出的都是 1 !
JavaScript 嵌套函数
所有函数都有权访问全局作用域。
事实上,在 JavaScript 中,所有函数都有权访问它们“上面”的作用域。
JavaScript 支持嵌套函数。嵌套函数可以访问其上的作用域。
在本例中,内部函数 plus() 可以访问父函数中的 counter 计数器变量:
function add() {
var counter = 0;
function plus() {counter += 1;}
plus();
return counter;
}
这样即可解决计数器困境,如果我们能够从外面访问 plus() 函数。
我们还需要找到只执行一次 counter = 0 的方法。
我们需要闭包(closure)。
JavaScript 闭包
还记得函数自我调用吗?该函数会做什么?
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
add();
add();
add();
// 计数器为 3
例子解释
变量 add 的赋值是自调用函数的返回值。
这个自调用函数只运行一次。它设置计数器为零(0),并返回函数表达式。
这样 add 成为了函数。最“精彩的”部分是它能够访问父作用域中的计数器。
这被称为 JavaScript 闭包。它使函数拥有“私有”变量成为可能。
计数器被这个匿名函数的作用域保护,并且只能使用 add 函数来修改。
闭包指的是有权访问父作用域的函数,即使在父函数关闭之后。
技巧1: 用闭包解决递归调用问题
function factorial(num) {
if(num<= 1) {
return 1
} else {
return num * factorial(num-1)
}
}
var anotherFactorial = factorial
factorial = null
anotherFactorial(4) // 报错 ,因为最好是return num* arguments.callee(num-1),arguments.callee指向当前执行函数,但是在严格模式下不能使用该属性也会报错,所以借助闭包来实现
// 使用闭包实现递归
function newFactorial = (function f(num){
if(num<1) {return 1}
else {
return num* f(num-1)
}
}) //这样就没有问题了,实际上起作用的是闭包函数f,而不是外面的函数newFactorial
技巧2:用闭包模仿块级作用域
es6没出来之前,用var定义变量存在变量提升问题:
for(var i=0;i<10; i++){
console.info(i)
}
alert(i) // 变量提升,弹出10
//为了避免i的提升可以这样做
(function () {
for(var i=0; i<10;i++){
console.info(i)
}
})()
alert(i) // underfined 因为i随着函数的退出,执行环境销毁,变量回收
猜你喜欢
- 2025-07-27 8个前端面试的题目(前端面试题2020及答案 知乎)
- 2025-07-27 深入理解Node.js中的垃圾回收和内存泄漏的捕获
- 2025-07-27 网易+腾讯+阿里,前端工程师面经!30K果然不是很好拿
- 2025-07-27 go errgroup 获取gorouting错误信息
- 2025-07-27 盛趣游戏unity客户端面试(盛趣游戏招聘岗位)
- 2025-07-27 Swift 性能探索和优化分析(swift运行效率)
- 2025-07-27 「前端开发」eval() 函数认知和学习以及注意事项
- 2025-07-27 解锁C++灵魂:函数指针场景及实例(c++函数指针和指针函数)
- 2025-07-27 2021 年 Node.js 开发人员学习路线图
- 2025-07-27 跨越十年的C++演进:C++11新特性全解析
- 最近发表
- 标签列表
-
- location.href (44)
- document.ready (36)
- git checkout -b (34)
- 跃点数 (35)
- 阿里云镜像地址 (33)
- qt qmessagebox (36)
- mybatis plus page (35)
- vue @scroll (38)
- 堆栈区别 (33)
- 什么是容器 (33)
- sha1 md5 (33)
- navicat导出数据 (34)
- 阿里云acp考试 (33)
- 阿里云 nacos (34)
- redhat官网下载镜像 (36)
- srs服务器 (33)
- pico开发者 (33)
- https的端口号 (34)
- vscode更改主题 (35)
- 阿里云资源池 (34)
- os.path.join (33)
- redis aof rdb 区别 (33)
- 302跳转 (33)
- http method (35)
- js array splice (33)