闭包是什么:指的是一种允许函数访问并操作该函数外部变量的一种环境。就比如下面这种情况,内部函数f
存在对外部函数fn
的变量n
的引用。
var n = 10
function fn(){
var n =20
function f() {
n++;
console.log(n)
}
f()
return f
}
var x = fn()
x()
x()
console.log(n)
/* 输出
* 21
22
23
10
/
形成闭包的原因:
在ES5中只存在两种作用域————全局作用域和函数作用域,当访问一个变量时,解释器会首先在当前作用域查找标示符,如果没有找到,就去父作用域找,直到找到该变量的标示符或者不在父作用域中,这就是作用域链,值得注意的是,每一个子函数都会拷贝上级的作用域,形成一个作用域的链条。
因此可以总结原因:外部函数虽然已经执行完毕,但内部函数仍然保留了对外部变量的引用,而这些变量并没有被垃圾回收机制释放。【当前作用域存在指向父级作用域的引用】
这里扩展一下堆栈内存:
闭包的作用:
闭包的使用场景【表现形式】:
var a = 0
function fn() {
var a = 1
function fn1() {
console.log(a)
}
return fn1
}
function fn2(params) {
var a = 2
params()
}
fn2(fn()) // 1 fn1函数使用fn的变量a形成闭包
window
的作用域。window
作用域。var a = 0;
(function() {
console.log(a)
})()
// 防抖:多次操作只触发最后一次,如输入框响应式搜索
function debounce(fn, time) {
let timer
return function () {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arguments)
}, time);
}
}
// 节流:多次操作只触发第一次,如点击登录按钮、获取验证码按钮
function throttle(fn, time) {
let timer
return function () {
if (timer) return
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, time);
}
}
// 使用方法示例:debounce(fn(2, 3), 1000)
function add(x) {
return function(y) {
return x + y;
};
}
const curriedAdd = add(2);
console.log(curriedAdd(3)); // 5
闭包可能存在的问题
如何避免内存泄漏问题?
beforeDestroy
清除定时器、移除事件监听。window.removeEventListener('scroll', this.handleScroll);
clearInterval(this.timer);
null
,如vue中beforeDestroy
周期时beforeDestroy() {
// 在组件销毁之前清理数据
this.data = null; // 将数据设置为null,使其在垃圾回收时可以被释放
},
经典面试题
5
如何让他输出1 2 3 4 5
for(var i = 1; i <= 5; i ++){
setTimeout(function timer(){
console.log(i) // 5 5 5 5 5
}, 0)
}
for(var i = 1; i <= 5; i ++){
(function (j) {
setTimeout(function timer(){
console.log(j) // 1 2 3 4 5
}, 0)
})(i)
}
let
,let
具有块级作用域,形成的5
个私有作用域都是互不干扰的。for(let i = 1; i <= 5; i ++){
setTimeout(function timer(){
console.log(i) // 1 2 3 4 5
}, 0)
}
for(var i = 1; i <= 5; i ++){
setTimeout(function(i){
console.log(i) // 1 2 3 4 5
}, 0, i)
}
var result = [];
var a = 3;
var total = 0;
function foo(a) {
for (var i = 0; i < 3; i++) {
result[i] = function () {
total += i * a;
console.log(total);
}
}
}
foo(1);
result[0]();
result[1]();
result[2]();
此题的输出结果为:3 6 9
,因为foo
形成闭包,total
被外层引用没有被销毁。
参考博客: