2024JS闭包完全解析 面试再也无烦恼

闭包的由来

JS中的闭包是由于函数作用域和作用域链的特性而产生的。

在JS中,每次定义一个函数时,都会创建一个新的函数作用域。函数内部可以访问函数外部的变量和函数,但是函数外部无法直接访问函数内部的变量和函数。这种作用域的嵌套关系形成了作用域链。

当一个函数内部定义了一个函数,并且内部函数引用了外部函数的变量或函数时,内部函数会持有对外部函数作用域的引用。即使外部函数执行完毕后,这个引用仍然存在于内部函数中,形成了闭包。闭包使得内部函数可以继续访问和操作外部函数的变量,即使外部函数已经不处于活动状态。

闭包的定义

来看看mdn上是怎么说的

闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment词法环境)的引用组合。

比如,当一个函数返回另一个函数时,如果被返回的函数引用了其父函数中的变量,那么这个被返回的函数就成为了一个闭包。

//函数作为返回值
function test() {
const a = 11;
return function () {
	return `${a} closure`;
};
}
const t = test();

console.log(t()); //这里就形成了闭包 输出11 closure

// 函数作为参数
function test1(fn) {
const b = 33;
fn();
}
const b = 22;

function fn() {

console.log(`${b} closure`);

}

test1(fn);// 22 closure
//`fn`函数在定义时引用了外部的变量`b`。当`test1`函数调用`fn`函数时,`fn`函数仍然可以访问并使用定义时所引用的外部变量`b`。因此,`fn`函数形成了闭包。

由例子也可以看出,闭包会随着函数的创建而被同时创建。

闭包两个特点
  1. 函数嵌套函数
  2. 内层函数可以访问外层函数的变量和参数,包括可以访问其定义时所处作用域以及父作用域变量
闭包两个作用
  1. 防止变量和参数被垃圾回收机制(变量持久化)
  2. 防止变量和参数被外部污染(变量只在闭包内部可访问)

闭包风险

  1. 可能有内存泄露的风险

⭐⭐️⭐️⭐⭐️️️相关面试回答

(1) 闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment词法环境)的引用组合,包括可以访问其定义时所处作用域以及父作用域中的变量。

(2) 闭包一般是函数嵌套,一个函数返回另外一个函数,内部函数访问外部函数的变量就形成了一个闭包
(3) 闭包的优点是可以私有化变量,将变量私有化到函数内部,并在私有化的基础上进行数据保持
(4) 闭包的缺点是容易造成内存泄露,因为闭包创建的变量会一直存在内存中,需要及时置空,否则会造成内存泄露,影响程序性能

举例作用

(5) 闭包在防抖节流函数柯里化,都应用里数据保持(变量持久化)这个特性
比如在防抖函数中,第一次点击的时候,我们会let一个time一个定时器,如果不采用闭包的话,下次触发函数会重新创建一个新的定时器,两个定时器的引用不同,是没有关联的,使用闭包可以直KKKK接在内存中找到之前创建的计时器,调用就可以直接拿到对应的定时器的时间

闭包经典问题

var arr = [];
for (var i = 0; i < 3; i++) {
  (function(i) {
    arr[i] = function() {
   console.log(i);
    };
  })(i);
}
arr[0]();//1
arr[1]();//2
arr[2]();//3
var res1 = [];
for (let i = 0; i < 3; i++) {
res1[i] = function () {
console.log(i);
};
}
res1[0]();//1
res1[1]();//2
res1[2]();//3

解决问题可以使用立即执行函数来创建一个独立作用域,让每个函数都能捕获到对应的 i 的值。或者用let创建块级作用域

面试题解析

function foo(n, o) {
console.log(o); //第一次undefined
return {
fun: function (m) {
return foo(m, n); // 1, n根据作用域链往上找 n = 0
},
};
}
var a = foo(0); //undefined
a.fun(1); //0
a.fun(2); //0
a.fun(3); //0

第二个

function foo(n, o) {

console.log(o); //undefined // 0 // 1 // 2 // 3

return {

fun: function (m) {

return foo(m, n); //上级作用域的参数一直在改变 //(1,0) // (2,1) //(3,2)

},

};

}
var a = foo(0).fun(1).fun(2).fun(3); //undefined 0 1 2

第三个自己做一下吧


function foo(n, o) {

console.log(o);

return {

fun: function (m) {

return foo(m, n); 

},
};
}

文章到这里就结束了,希望对你有所帮助。

  • 12
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值