子函数可以访问到其他函数作用域的变量,就叫做闭包
闭包指子函数可以访问外部作用域变量的函数特性,即使在子函数作用域外也可以访问。如果没有闭包那么在处理事件绑定,异步请求时都会变得困难。
JS中的所有函数都是闭包
闭包一般在子函数本身作用域以外执行,即延长作用域
最简单的闭包:
function hd() {
let name = '后盾人';
return function () {
return name;
}
}
let hdcms = hd();
console.log(hdcms()); //后盾人
使用闭包返回数组区间元素:
let arr = [3, 2, 4, 1, 5, 6];
function between(a, b) {
return function(v) {
return v >= a && v <= b;
};
}
console.log(arr.filter(between(3, 5)));
下面是在回调函数中使用闭包,当点击按钮时显示当前点击的是第几个按钮:
<body>
<button message="后盾人">button</button>
<button message="hdcms">button</button>
</body>
<script>
var btns = document.querySelectorAll("button");
for (let i = 0; i < btns.length; i++) {
btns[i].onclick = (function(i) {
return function() {
alert(`点击了第${i + 1}个按钮`);
};
})(i);
}
</script>
移动动画 计时器中使用闭包来获取独有变量(
1.点击抖情况,因为哪个时候left还定义在子作用域下面,相当于创建了很多个环境,即每点击一次加一次定时器和一个新的left,总是重置为1,当然会出现点击倒退来回抖动。
2.点击一直加速情况,此时虽然left在父环境下,但是定时器函数还在子环境中,也就是每次都创建一个新的定时器,比如设置为1000毫秒加一个速度,当我们点击十次时,此时加了是个定时器,相当于此时为100毫秒加一个速度 )
<body>
<style>
button {
position: absolute;
}
</style>
<button message="后盾人">houdunren</button>
<!-- <button message="hdcms">hdcms</button> -->
</body>
<script>
let btns = document.querySelectorAll("button");
btns.forEach(function(item) {
let bind = false;
item.addEventListener("click", function() {
if (!bind) {
let left = 1;
bind = setInterval(function() {
item.style.left = left++ + "px";
}, 100);
}
});
});
</script>
闭包问题
1.内存泄漏
闭包特性中上级作用域会为函数保存数据,从而造成的如下所示的内存泄漏问题
<body>
<div desc="houdunren">在线学习</div>
<div desc="hdcms">开源产品</div>
</body>
<script>
let divs = document.querySelectorAll("div");
divs.forEach(function(item) {
item.addEventListener("click", function() {
console.log(item.getAttribute("desc"));
});
});
</script>
此时因为click事件回调函数是一直在监听的,不会被销毁,此时我们每次点击都会创建很多个回调函数的独立的内存,当程序很大很复杂时会影响性能,这就闭包带来的内存泄漏的问题
下面通过清除不需要的数据解决内存泄漏问题
let divs = document.querySelectorAll("div");
divs.forEach(function(item) {
let desc = item.getAttribute("desc");
item.addEventListener("click", function() {
console.log(desc);
console.log(item);//null
});
item = null;//把元素设置为null,空对象是不会占有内存的,此时清除了内存泄漏的问题,使性能变得更加的快速
});
2.this指向
this 总是指向调用该函数的对象,即函数在搜索this时只会搜索到当前活动对象。
let hd = {
user: "后盾人",
get: function() {
return function(){
return this.user;//
}
}
};
console.log(hd.get()()); //undefined
此时this在function下,是指向window的,此时return的是window的user属性,显然是输出undefined
解决方法: 1.在父级作用域下用变量保存this
2.用箭头函数,箭头函数的this指向上下文
1. let hd = {
user: "后盾人",
get: function() {
let that = this;//这个是对象的方法,这个环境下this是指向hd对象的,即会有user属性
return function() {
return that.user;//后盾人
};
}
};
console.log(hd.get()());//后盾人
2. let hd = {
user: "后盾人",
get: function() {
return () => this.user;//后盾人
}
};
console.log(hd.get()()); //后盾人