🔥🔥你真的懂闭包吗?4分钟带你彻底解决闭包疑难杂症,面试再也无烦恼

闭包的由来

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

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

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

闭包的定义

来看看mdn上是怎么说的

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

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

js 复制代码
//函数作为返回值
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接在内存中找到之前创建的计时器,调用就可以直接拿到对应的定时器的时间

闭包经典问题

js 复制代码
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创建块级作用域

面试题解析

js 复制代码
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

第二个

js 复制代码
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

第三个自己做一下吧

js 复制代码
function foo(n, o) {

console.log(o);

return {

fun: function (m) {

return foo(m, n); 

},
};
}

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

相关推荐
f8979070702 分钟前
layui动态表格出现 横竖间隔线
前端·javascript·layui
鱼跃鹰飞9 分钟前
Leecode热题100-295.数据流中的中位数
java·服务器·开发语言·前端·算法·leetcode·面试
TANGLONG22219 分钟前
【C语言】数据在内存中的存储(万字解析)
java·c语言·c++·python·考研·面试·蓝桥杯
二十雨辰43 分钟前
[uni-app]小兔鲜-04推荐+分类+详情
前端·javascript·uni-app
霸王蟹1 小时前
Vue3 项目中为啥不需要根标签了?
前端·javascript·vue.js·笔记·学习
小白求学11 小时前
CSS计数器
前端·css
Anita_Sun2 小时前
🌈 Git 全攻略 - Git 的初始设置 ✨
前端
狐小粟同学2 小时前
链表面试编程题
数据结构·链表·面试
lucifer3112 小时前
深入解析 React 组件封装 —— 从业务需求到性能优化
前端·react.js
等什么君!2 小时前
复习HTML(进阶)
前端·html