0.什么是闭包
闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的.
只要出现引用了外部变量的函数,那么这个现象叫做闭包现象
1.闭包的特点
弊端:外部函数结束,内部函数依然存在,而且占用了外部函数的变量,导致外部函数不能释放内存,产生内存泄漏.
优势:1.变量是在函数内部定义(外部函数)属于局部变量,不会被外部污染
2.内部函数可以访问定义它们的外部函数的参数和变量(除了this
和arguments
)
2.解决闭包的麻烦
当内部函数不再使用的时候,主动释放闭包所占用的内存.(看demo)
3.demo
这里的内部函数是一个匿名函数,嵌套在外部函数
setElement
中,其中引用了外部函数的变量index
和arr
,在这个内部函数被返回并在其他地方被使用时,它依然用着这两个变量,所及即使外部函数完成调用后,依旧没有释放内存.
这里创建的函数会被保存在变量getElement
中,把getElement设置为null
会接触对函数的引用,从而让垃圾回收系统释放,同时作用域也会被销毁.
<body>
<button>自增</button>
<h1></h1>
<script>
const btn = document.querySelector('button');
const h1 = document.querySelector('h1');
// 闭包的特点:外部函数结束,内部函数依然存在,而且占用了外部函数的变量
//(导致外部函数不能释放内存)
function setElement() {
// 1. 定义一个数组
let arr = [
{ name: "金" },
{ name: "木" },
{ name: "水" },
{ name: "火" },
{ name: "土" }
];
// 2. 定义一个下标
let index = -1; // 不是数组真正有效的下标
// 3. 返回一个函数
return function () {
// 3.1 修改index
index++; // 当前函数没有index,访问的是外部的index
// 3.2 判定
if (index > arr.length - 1) {
index = 0; //这时显示下标0,"金"
}
// 3.3 返回当前的数据
return arr[index].name;
};
}
// 调用函数setElement
let getElement = setElement();
// 代码执行到这:函数setElement()执行已经结束
// 按理说:应该释放setElement的内存(index,arr)
// 但是:因为当前函数的运行返回了一个函数:里面要用到index和arr:导致函数不能
//释放内存(内存一直被占用): 闭包
// console.log(getElement);
h1.innerText = getElement();//渲染
// 点击事件
// 点击调用函数,下标++显示不同数据
btn.onclick = function () {
h1.innerText = getElement();
};
// 假设后续还有很多代码要运行:上述内存一直会占用(虽然代码很安全,不存在污染的问题)
// 解决闭包的麻烦:主动释放闭包所占用的内存
// 释放内存把下面这行代码注释打开
// getElement = null;
// getElement不再指向闭包函数function,闭包函数也就不需要占用变量arr和index:setElement函数可以得到释放
</script>
</body>
4.this对象
在闭包中使用this会比较复杂
- 如果内部函数没有使用箭头函数定义,则
this
会在运行时绑定执行函数的上下文.- 如果在全局函数中调用,则this在非严格模式下等于window,严格模式下尾undefined
- 如果作为某个对象方法调用,则this指向该对象
window.identity = '这是window'
let obj = {
identity: '这是obj',
getIdentity() {
// 返回内部函数
return function () {
return this.identity
}
}
}
console.log(obj.getIdentity()());//这是window
// 注意最后还有()
这里的this并没有指向当前作用域,是因为
this
和arguments
都是不能直接在内部函数中访问,如果想要访问arguments可以用内包内可以访问的变量保存.例如:let that = this
<script>
window.identity = '这是window'
let obj = {
identity: '这是obj',
getIdentity() {
let that = this
// 返回内部函数
return function () {
return that.identity
}
}
}
console.log(obj.getIdentity()());//这是obj
// 注意最后还有()
</script>