什么是闭包: (closure)
- 闭包实际上就是一种函数,所以闭包技术也是函数技术的一种,闭包能做的事情函数几乎都能做
- 闭包技术花式比较多,用法也比较灵活,一般开发人员在学习闭包的时候都会遇到瓶颈,主要是因为闭包技术的分界线并不明显,几乎无法用一个特点去区分
- 当一个嵌套的内部函数引用了嵌套的外部函数的变量(函数)时,就产生了闭包
- 解决全局变量污染,性能提升等等
如何产生闭包:
当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包
闭包到底是什么:
使用chrome调试看看
-
理解一:闭包是嵌套的内部函数
-
理解二:包含被引用变量(函数)的对象
注意:闭包存在于嵌套的内部函数中
产生闭包的条件:
函数嵌套 内部函数引用了外部函数的数据(变量/函数)
常见的闭包使用形式:
- 将函数作为另一个函数的返回值
- 将函数的形参作为实参传递给另一个函数调用
闭包的内存管理
- 垃圾回收机制处理方式
- 针对闭包来做怎么样的处理
function fn1() {
var num = 10;
function fn2() {
console.log(num);
}
};
fn1();
常见的闭包使用形式:
- 将函数作为另一个函数的返回值
- 将函数的形参作为实参传递给另一个函数调用
- 通过闭包来保住大的函数里局部函数(和变量)的生命周期
让小的函数作为大的函数的返回值
1.将函数作为另一个函数的返回值:
function fn1() {
var num = 10;
function fn2() {
num++;
console.log(num);
}
return fn2;
};
var f = fn1();
f(); //11
f(); //12
2.将函数的形参作为实参传递给另一个函数调用:
function logMsgDelay(msg,time) {
setTimeout(function () {
// debugger;
console.log(msg);
},time);
}
logMsgDelay('啊啊啊',1000);
闭包的应用-定义JS模块
- 将所有的数据和功能都封装在一个函数内部(私有)
- 只向外暴露一个包含多个方法的对象或函数
- 模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
var toolObj = myTool();
toolObj.get();
toolObj.send();
闭包应用-封装全局作用域:
作用域链条:全局作用域和局部作用域
- 凡是存在作用域的地方一定有作用域链条,变量的查找都是沿着这条作用域链条自内而外的
- 寻找变量都是递归遍历寻找,当前作用域找不到,就到上一个作用域遍历寻找,直至顶层
- 作用域链条太长,会影响程序运行效率
- 把一些不需要暴露在全局的变量封装成“私有变量”
(function () {
var str = '张三';
console.log(str);
})();
(function () {
var str = '王五';
console.log(str);
})();
(function (document) {
document.getElementById();
})(document);
(function (window) {
(function (window) {
(function (window) {
})(window);
})(window);
})(window);
(function (w) {
})(window);
</script>
<script src="js/MyTool2.js"></script>
<script>
// console.log(window);
myTool.get();
myTool.send();
</script>
闭包的作用分析
- 使用函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的什么周期)
- 让函数外部可以操作(读写)到函数内部的数据(变量/函数)
问题:
- 函数执行完之后,函数内部声明的局部变量是否还存在? 一般是不存在,存在于闭包中的变量才可能存在
- 在函数外部能直接访问函数内部的局部变量吗? 不能,但我们可以通过闭包让外部操作它
产生:在嵌套内部函数定义执行完时就产生了(不是在调用)
死亡:在嵌套的内部函数成为垃圾对象时
function fn1() {
var num = 10;
function fn2() {
num++;
console.log(num);
}
return fn2;
};
var f = fn1();
f();
//使用完毕后,让全局变量为null 删除里面的垃圾对象
f = null;
闭包的高级排他方法:
var allLis = document.getElementsByTagName('li');
var lastOne = 0;
for (var i = 0; i < allLis.length; i++) {
(function (index) {
allLis[index].onmouseover = function () {
//清除
allLis[lastOne].className = '';
//设置
this.className = 'current';
//赋值 每次进来清除上一个被选中的class
lastOne = index;
}
})(i);
}
闭包的缺点
- 缺点:函数执行完之后,函数内部的局部变量没有释放,占用内存时间会变长,容易造成内存泄漏
- 解决:及时释放
function fn1() {
var arr = new Array[99999999999999999];
function fn2() {
console.log(arr);
}
return fn2;
}
var f = fn1();
f();
//释放
f = null;
1. 内存溢出:
一种程序运行出现的错误
当程序运行需要的内存超过了剩余的内存时,就出抛出内存溢出的错误
2. 内存泄漏:
占用的内存没有及时释放
内存泄漏累积多了就容易导致内存溢出
常见的内存泄漏:
- 占用内场很大的全局变量
- 没有及时清理的计时器/定时器
- 闭包