目录
一、闭包的官方定义
闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
二、闭包的个人理解
什么是闭包,闭包是一种现象,指的是一个函数能够访问外部的变量这么一种现象就是闭包。在js中,从理论上讲,所有的函数都是闭包,因为js语言的特性就是函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。但在实践的角度,下面的这种情况才算是闭包(即在函数内部,切实的访问了外部变量):
function foo() {
var name = "小G"
var age = 18
function bar() {
console.log(name)
console.log(age)
}
return bar
}
var fn = foo()
fn()
但在使用闭包的过程中容易造成内存泄漏,可以手动将fn函数以及foo函数指向为空地址既可以释放闭包产生的内存泄漏,即:
function foo() {
var name = "小G"
var age = 18
function bar() {
console.log(name)
console.log(age )
}
return bar
}
var fn = foo()
fn()
//解决内存泄漏
fn = null
foo = null
三、闭包的实际应用场景
1.防抖、节流
防抖
var timer; // 定时器
function change (e) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function () {
console.log(e.target.value);
timer = void 0;
}, 1000)
}
document.querySelector("#test")
.addEventListener('keyup', change);
节流
var start, timer, wait = 200
function scroll() {
var self = this;
var args = arguments;
if (!start) {
//第一次触发,设置start时间
start = Date.now()
}
// 当前时间减去开始时间大于
// 等于设定的周期则执行并且初始化start、timer
if (Date.now() - start >= wait) {
console.log('触发了')
start = timer = void 0;
} else {
timer && clearTimeout(timer)
timer = setTimeout(function () {
scroll.apply(self, arguments)
},wait)
}
}
document.addEventListener('scroll', scroll)
2.模块封装,比如封装公共方法
金额三位一逗
// 三点一逗
function get_thousand_num(num) {
return num.toString().replace(/\d+/, function (n) {
// 先提取整数部分
return n.replace(/(\d)(?=(\d{3})+$)/g, function ($1) {
// 对整数部分添加分隔符
return $1 + ','
})
})
}
temp = get_thousand_num(temp)
return temp
}
3.在循环中创建闭包,避免出现意外的结果
for (var i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i);
}, i * 1000);
}
//会一直输出6,这不是想要的结果
for (var i = 1; i <= 5; i++) {
(function (i) {
setTimeout(function timer() {
console.log(i);
}, i * 1000);
})(i)
}
//利用闭包,可以解决
四、总结
闭包几乎是面试过程中必问的题目,其中牵扯的知识面及其广泛,面试官几乎可以通过你对闭包的了解判断你的个人能力。当然,闭包所包含的还有更多更深层的知识这里并未记录,比如内存泄漏、v8引擎的垃圾回收机制、作用域、作用域链等等,将会在后续的学习记录中陆续补充