这是我的第一篇掘金博客,开启掘金写作之路。
闭包
闭包可以理解为:
- 访问另一个函数的作用域的变量或函数;
- 延长变量生命周期(异步环境使用)剖析 ;
- 封装对象的私有属性和私有方法(进阶)
闭包用途示例
访问另一个函数的作用域的变量或函数:实现一个计数器
let current = 0
function add(){
current += 1
}
add()
add()
add()
console.log(current) // 3
以上示例看似实现了,但是我们可以在代码中的任意一个位置改变current的值,似乎并不完美,那么放到函数里面会怎么样
function add(){
let current = 0
current += 1
}
add()
add()
add()
console.log(current) //报错 current is not defined
这是为什么呢?因为ES6 新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let,这里不做赘述,详情请戳:let 和 const 命令
所以我们该怎么实现这个计数器呢?这时候我们就要用到闭包去实现计数器这个问题,代码如下
// 同时实现计数增加,计数减少,获取计数当前的值
const c = (function () {
let current = 0
return {
// 增加
add: function () {
current += 1
},
// 减少
cut: function () {
current -= 1
},
// 获取当前值
value: function () {
return current
}
}
})()
console.log(c.value()) // 0
c.add()
c.add()
console.log(c.value()) // 2
c.cut()
console.log(c.value()) // 1
延长变量生命周期(异步环境使用)剖析:
看到很多关于闭包用途的博客发现,常见的闭包使用举例如下
<div>
<li>1</li>
<li>2</li>
<li>3</li>
</div>
var liList = document.querySelectorAll('li')
for (var i = 0; i < liList.length; i++) {
liList[i].onclick = function () {
console.log(i)
}
}
最终结果是不管单击哪个li元素都会打印 3,为什么呢?
因为var申明变量作用域的问题,var申明变量,变量申明提前导致,闭包可以解决这个问题,示例如下
// 循环遍历添加点击事件
var liList = document.querySelectorAll('li')
for (var i = 0; i < liList.length; i++) {
(function (i) {
liList[i].onclick = function () {
console.log(i)
}
})(i)
}
// 依次点击,分别打印 0 1 2
但是还有一个更简便的方法,使用let申明变量,示例如下
const liList = document.querySelectorAll('li')
for (let i = 0; i < liList.length; i++) {
liList[i].onclick = function () {
console.log(i)
}
}
// 依次点击,分别打印 0 1 2
这是为什么呢?因为ES6 新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let,这里不做赘述,详情请戳:let 和 const 命令
封装对象的私有属性和私有方法(进阶):
实现只读,只写,可读可写 实现代码如下
const property = (function (opts) {
let value = '闭包'
const hasSet = opts.hasSet || false
const hasGet = opts.hasGet || false
const res = {}
if (hasGet) {
res.get = function () {
return value
}
}
if (hasSet) {
res.set = function (v) {
value = v
}
}
return res
})({ hasSet: true, hasGet: true })
console.log(property.get()) // 闭包
property.set('闭包DEMO')
console.log(property.get()) // 闭包DEMO
闭包的原理其实还是作用域
使用闭包的优点是可以避免全局变量污染
闭包的缺点:1、内存泄露;2、存在循环引用;
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。