1.谈谈你对闭包的理解
闭包可以理解为函数中的函数,其中内部函数可以访问外部函数的变量,闭包是将内部函数和外部函数连接起来的桥梁。
2. 闭包的优点
- 可以访问到函数内部的变量(通过函数内部的函数俩访问函数的变量);
- 可以避免全局变量被污染;
3.闭包的缺点
- 容易导致内存泄漏:因为闭包会长时间保持对外部作用域的引用,如果没有及时释放这些引用的话,会导致垃圾回收机制回收内存失败,造成内存泄漏。解决办法就是:在不需要使用闭包时,要取消对其变量的引用,例如将引用置为null。
- 内存消耗大:层函数每次运行都会形成一个闭包,这个闭包会保留外部作用域的变量,因此内存消耗很大。因为不能滥用闭包,否则会造成网页性能问题。
3.1 垃圾回收机制
内存泄漏:占用的内存没有被及时释放,会造成内存泄漏;
内存溢出:需要的内存超出了剩余内存,会造成内存溢出;
垃圾回收机制的回收算法:
- 引用计数法:“把对象是否不被需要”简化为“对象有没有其他对象引用到它”,如果该对象的引用数为0,则对其进行垃圾回收。
- 标记清除法:“把对象是否不被需要”简化为“对象是否可以获得”,垃圾回收器从根开始,找到所有从根开始引用的对象,然后查找这些对象引用的对象,一层一层找下去,找到所有可以获得的对象并收集所有不能获得的对象,这些不能获得的就是垃圾回收器需要回收的。
4.闭包的应用
- 立即执行函数
利用for循环创建几个立即执行函数,并且把变量当做参数传入,就是一个闭包。
for (var i = 0; i < list.length; i++) {
// 利用for循环创建了4个立即执行函数,每个立即执行函数都是一个闭包
(function(i) {
list[i].onclick = function() {
console.log(i);
}
})(i);
}
- 函数柯里化
函数式编程里面的概念,只传递一部分参数来调用它,然后返回一个函数让它处理剩下的参数。就是把一个多参数函数转化为一个单参数函数。柯里化的作用:参数复用、提前返回和延迟执行。
// 柯里化之前
function add(x, y) {
return x + y;
}
add(1, 2) // 3
// 柯里化之后
function addX(y) {
return function (x) {
return x + y;
};
}
addX(2)(1) // 3
- 防抖和节流
防抖:为一个事件设置一个时间N,N秒后再执行该事件,若在N秒内重复触发,则重新计时。(一定时间内多次触发一个函数,只执行最后一次)。例如:浏览器搜索框。
节流:为一个事件设置一个时间N,N秒内只执行一次,若在N秒内重复触发,则重复触发的不生效。(一定时间内多次触发一个函数,时间到了之后只执行一次函数)。例如:页面滚动。
// 防抖
function debounce(fn, wait) {
let timer = null;
const agrs = arguments;
const _this = this;
return function() {
if (timer) {
timer = null
}
timer = setTimeout(() => {
fn && fn.apply(_this, agrs);
}, wait);
}
}
// 节流
function throttle(fn, wait) {
let timer = null;
const agrs = arguments;
const _this = this;
return function() {
if (timer) {
return;
}
timer = setTimeout(() => {
fn && fn.apply(_this, agrs);
timer = null;
})
}
}