01-闭包-closure
<script>
// 闭包:closure,函数内部用到了函数外部的数据(变量存着),这种现象就叫做闭包现象
let arr = [1, 2, 3]
function getArrMax() {
let max = -Infinity
for (let i = 0; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i]
}
}
return max
}
// 函数内部arr用到的是函数外部的变量:产生闭包现象
// 上述闭包:广义闭包(定义比较宽松)
// 狭义闭包:面试的时候想要得到的结果是狭义闭包
// 狭义闭包条件
// 1. 函数内部定义了局部变量
// 2. 函数返回一个内部函数,内部函数里面用到了外部函数的变量
function outer() {
console.log('outer函数')
// 局部变量
let arr = ['a', 'b', 'c']
// 内部函数
let inner = function () {
// 内部函数使用到了外部函数的变量
// 狭义闭包
console.log(arr)
}
return inner
}
// 函数运行的步骤
// 1. 找到函数
// 2,开辟内存运行函数
// 3. 运行结束应该销毁函数所占用的内存
let res = outer()
// 57行:等代码执行到这,说明上面代码执行应该结束了:outer()函数占用的内存应该销毁掉了
// console.log(res)
res()
// 闭包的优缺点
// 1. 优点:数组定义在函数内部:数据是安全的(不会被修改,也不能被污染)
// 2. 缺点:函数虽然运行结束,但是因为内部函数还需要用到外部函数的数组变量:不能被销毁:占用内存
</script>
注意:
1.闭包:closure,函数内部用到了函数外部的数据(变量存着),这种现象就叫做闭包现象
2. // 函数内部arr用到的是函数外部的变量:产生闭包现象
// 上述闭包:广义闭包(定义比较宽松)
// 狭义闭包:面试的时候想要得到的结果是狭义闭包
// 狭义闭包条件
// 1. 函数内部定义了局部变量
// 2. 函数返回一个内部函数,内部函数里面用到了外部函数的变量
// 闭包的优缺点 // 1. 优点:数组定义在函数内部:数据是安全的(不会被修改,也不能被污染) // 2. 缺点:函数虽然运行结束,但是因为内部函数还需要用到外部函数的数组变量:不能被销毁:占用内存
02-闭包-实际应用
<body>
<button>按钮</button>
<h1></h1>
<script>
// 函数内部使用外部变量(广义),内部函数使用了外部函数的局部变量(狭义)
// 需求:将数组中的数据,在点击后轮番显示到h1中
let arr = ['金', '木', '水', '火', '土']
// 1. 获取相关元素:按钮,h1
let btn = document.querySelector('button')
let h1 = document.querySelector('h1')
// 2. 定义一个变量记录下标:给h1默认显示第一个元素
let index = 0
h1.innerText = arr[index]
// 3. 给按钮做点击事件
btn.onclick = () => {
// 4. 事件处理:修改index下标,++;将新的index对应的数组元素显示到h1中
index++
if (index == arr.length) index = 0
h1.innerText = arr[index]
}
</script>
</body>
03-闭包-实际应用-数据安全
<body>
<button>按钮</button>
<h1></h1>
<script>
(function () {
// 函数内部使用外部变量(广义),内部函数使用了外部函数的局部变量(狭义)
// 需求:将数组中的数据,在点击后轮番显示到h1中
// 安全解决:由全局变成局部
// 1. 将数组放到函数中:变成局部变量(安全)
const getElement = () => {
const arr = ['金', '木', '水', '火', '土']
// 2. 函数实现的功能:动态的从数组中取出数据,返回给外部使用
// 2.1 定义一个局部变量:保存下标
let index = -1
// 2.2 定义一个内部函数:负责处理数据
return () => {
// 可以使用外部局部变量
index++
// 包要整安全
if (index == arr.length) index = 0
// 返回index对应的数组元素
return arr[index]
}
}
// 剩下的就是业务问题:用户到底是点击操作还是别的?用户到底是显示到h1中还是别的地方?
// 第一次显示数据
let getArrInfo = getElement()
document.querySelector('h1').innerText = getArrInfo()
document.querySelector('button').onclick = () => {
document.querySelector('h1').innerText = getArrInfo()
// 如何解决闭包占用内存的问题?
// 解决方案:释放对内部函数占用的变量:JS垃圾回收的机制是:一旦某个数据不会被其他变量占着:系统会自动回收内存
// getArrInfo = null
// 不是所有的闭包都必须释放
// 如果必要只为了使用一次(保证数据安全),用完一定要记得销毁
// 如果是用户需要不断使用:不可被效果
}
})()
</script>
</body>
注意:
1. 闭包:解决安全问题(数据安全)
2. 闭包:函数内部套函数,狭义闭包
3. 闭包:解决了安全问题,代价
3.1 代码复杂度增加(开发难度增加)
3.2 长期占用内存
4. 占用内存的解决方案:将指向内部函数的变量销毁
4.1 内部函数没有被变量引用:会被内存回收,占用的外部局部变量也会被回收
4.2 不一定需要销毁:不断使用的就不能销毁