你真的了解闭包吗,你知道闭包在实际开发中有什么用么,闭包是否会造成内存泄漏呢。
如果你想了更进一步了解闭包,请接着往下看吧。
本文主要参考《JavaScript设计模式与开发实践》。
(一) 前言:
闭包是一个可以访问到其他函数内部变量的函数
闭包一直在前端圈内耳熟能详,甚至可以说是面试必考经典。
但在我的前端程序员生涯的很长一段时间里,我对闭包的印象就是,我们在们面试中常说的那句。
闭包是一个可以访问到其他函数内部变量的函数
随着开发项目的不断增加,经验的不断积累偶尔也会用到闭包,但对闭包的感知是零零碎碎不成体系的。于是有了总结闭包这个知识点的想法。
本文是我个人依据个人日常开发经验,网络查询资料,综合整理的一篇文章,希望能给大家带来一些帮助
(二) 闭包
首先直观来看闭包的确是我们在面试中常说的那句,闭包是一个可以访问到其他函数内部变量的函数。
为何会有上面那句话,细化来说个人认为理解两个点就好了,其一是变量的作用域,是二是变量的生命周期
1. 变量的作用域
首先函数内的变量是局部变量,在该函数外我们是无法访问到的(下面的例子解释了这一点)
// 变量作用域演示
var func = function () {
var a = 1
console.log('func', a) // 输出: func 1
}
func()
console.log(a) // 输出: ReferenceError: a is not defined
作用域的概念我想大家都知道,就不详细叙述了。
2. 变量的生命周期
变量一般在函数执行完毕后如果没有额外引用,就被销毁了,下面的例子可以比较清晰的反应出这一点
// 变量的生命周期
let func = function () {
let a = 0
a++
console.log('输出内容', a)
}
func() // 输出内容 1
func() // 输出内容 1
func() // 输出内容 1
let func1 = function () {
let a = 0
return function () {
a++
console.log('输出内容', a)
}
}
let funcClosure = func1()
funcClosure() // 输出内容 1
funcClosure() // 输出内容 2
funcClosure() // 输出内容 3
为什么闭包中的变量没被销毁呢这个涉及到垃圾回收机制,即我们常说的标记清除与引用计数
3. 面试常考
曾经面试喜欢考这样一道题目, 当然一般的题目给有序的DOM节点绑定click事件
;
onclick的事件是异步触发的, for循环以迅雷不及掩耳的速度执行完毕所以每次打印的是最终的数字
然而今天变量申明用 let
, 这一问题得到了完美的解决, 下面的例子用setTimeout
模拟异步执行
// 面试常考题目: 问最后输出的是什么
function closure() {
for(var i = 0; i < 10; i++) {
setTimeout(function () {
console.log('输出内容', i) // 全部输出10
}, 0)
}
}
closure()
// 老版解决方法
function closure1() {
for(var i = 0; i < 10; i++) {
(function (i) {
setTimeout(function () {
console.log('输出内容', i)
}, 0)
})(i) // 最后输出1, 2, 3, 4, 5 ... 10
}
}
closure1()