🔥🔥你真的懂闭包吗?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); 

},
};
}

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

相关推荐
阿珊和她的猫1 小时前
v-scale-scree: 根据屏幕尺寸缩放内容
开发语言·前端·javascript
PAK向日葵3 小时前
【算法导论】PDD 0817笔试题题解
算法·面试
加班是不可能的,除非双倍日工资6 小时前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi6 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip6 小时前
vite和webpack打包结构控制
前端·javascript
excel7 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国7 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼7 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy7 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT8 小时前
promise & async await总结
前端