当前位置:首页 » 《随便一记》 » 正文

前端-打卡每日面试题-闭包(2024.1.25)

17 人参与  2024年02月13日 08:26  分类 : 《随便一记》  评论

点击全文阅读


一、闭包是什么?

1、概念

闭包是指在函数内部定义的函数,能够访问到外部函数的变量,并且保持对这些变量的引用,即使外部函数已经执行完毕。闭包形成了一个封闭的作用域,使得内部函数可以访问外部函数的局部变量,从而延长了这些变量的生命周期。

function outer() {  let x = 10;  function inner() {    console.log(x); // 内部函数可以访问外部函数的变量 x  }  return inner; // 返回内部函数}const closureFunction = outer(); // 调用外部函数,并将内部函数保存在变量中closureFunction(); // 执行保存的内部函数,依然可以访问外部函数的变量 x

二、为什么有闭包?

闭包在 JavaScript 中的存在是因为 JavaScript 采用了词法作用域的机制。词法作用域指的是变量的作用域是在代码编写阶段就确定的,而不是在执行阶段确定的。

当函数被定义时,它会创建一个闭包,保存了函数内部的局部变量和当前作用域链。这个闭包使得函数能够在定义它的词法作用域之外的地方被调用时,仍然能够访问到其内部的变量。

个人(理解记忆)

这个应该是牵扯到作用域的概念,一个内部函数无法访问到外部函数定义的变量,在没有闭包的情况下,函数只能访问其定义时的作用域,而无法在定义后继续访问外部作用域的变量。

比如,你进了一个房间(外部函数),在房间里有一个特殊的盒子(内部函数),你把一些东西放进这个盒子里。

当你走出房间,房间的大门关闭了(外部函数执行完毕),但是这个盒子里的东西你还能记得,而且你可以随时打开这个盒子,取出里面的东西。这个魔法盒子就好比闭包,记住了外部函数的一些东西,就算外部函数执行完毕了,闭包还能保留这些记忆

function outer() {  let x = 10;  function inner() {    console.log(x); // 内部函数尝试访问外部函数的变量 x,但会报错  }  inner(); // 直接调用内部函数,无法访问外部函数的变量 x}outer();

三、闭包的优点和缺点

优点:

1. 数据封装

闭包允许将变量隐藏在内部函数中,只暴露必要的接口,提高代码的安全性和可维护性。

function createCounter() {  let count = 0;  return function() {    count++;    console.log(count);  };}const counter = createCounter();counter(); // 输出: 1counter(); // 输出: 2
2. 保持状态

闭包可以保持外部函数调用时的状态,使得状态在多次调用之间得以保留

function createIncrementer(initialValue) {  let value = initialValue;  return function() {    value++;    console.log(value);  };}const incrementByTwo = createIncrementer(2);incrementByTwo(); // 输出: 3incrementByTwo(); // 输出: 4
3. 实现局部变量

通过闭包,可以模拟实现局部变量的效果,创建一个局部作用域。

function outer() {  let outerVariable = 'I am from outer';  function inner() {    let innerVariable = 'I am from inner';    console.log(outerVariable); // 访问外部变量    console.log(innerVariable); // 访问内部变量  }  inner();}outer();
4. 函数工厂

闭包允许创建函数工厂,即动态生成具有特定行为的函数

function multiplier(factor) {  return function(x) {    return x * factor;  };}const double = multiplier(2);console.log(double(5)); // 输出: 10
缺点 :

内存消耗: 闭包中的变量不会被垃圾回收,直到闭包不再被引用。如果闭包中包含大量变量或者循环引用,可能导致内存泄漏。

性能问题: 由于闭包涉及维护外部函数的作用域链,可能会导致性能损失,尤其是在嵌套层次较深或循环中。

滥用导致的可读性降低: 过度使用闭包可能导致代码的可读性下降。程序员需要理解整个作用域链,以便正确理解变量的值和生命周期。

可能导致意外的行为: 如果不小心修改了闭包中的变量,可能导致意外的行为,因为这些变量在外部函数执行完毕后仍然存在。

维护困难: 在大型项目中,如果滥用闭包,可能导致难以维护和调试的代码。特别是在多人协作的项目中,过度使用闭包可能增加理解的难度。

四、项目中的使用

防抖、节流、柯里化函数都是闭包

防抖(Debouncing): 防抖是一种技术,用于限制一段时间内函数的调用次数。通常在处理输入框输入、滚动等频繁触发的事件时使用。通过使用闭包来存储计时器,可以确保在一定时间内只执行最后一次函数调用。

function debounce(fn, delay) {  let timer;  return function() {    clearTimeout(timer);    timer = setTimeout(() => {      fn.apply(this, arguments);    }, delay);  };}

节流(Throttling): 节流是一种控制函数调用频率的技术,确保一定时间内只执行一次函数。也可以使用闭包来存储状态,例如上一次函数调用的时间戳

function throttle(fn, delay) {  let lastTime = 0;  return function() {    const now = Date.now();    if (now - lastTime >= delay) {      fn.apply(this, arguments);      lastTime = now;    }  };}

柯里化(Currying): 柯里化是将一个多参数函数转化为一系列单参数函数的过程。通过使用闭包,可以存储每个部分函数的参数,直到所有参数都被收集完成,然后执行原始函数。

function curry(fn) {  return function curried(...args) {    if (args.length >= fn.length) {      return fn.apply(this, args);    } else {      return function(...moreArgs) {        return curried.apply(this, args.concat(moreArgs));      };    }  };}

五、总结(以上便于理解记忆)

闭包的概念?怎么形成闭包?闭包的优缺点?项目中哪里使用闭包?

闭包就是函数嵌套函数被嵌套的函数叫做闭包函数。外部函数里面嵌套一个内部函数,外部函数在定义一个变量,再将内部函数作为整体作为返回值返回出去,外部定义一个全局变量接受,就能是这个变量生命周期延长,形成闭包。闭包的优点就是有:

数据封装: 闭包可以用于创建私有变量,实现数据封装,防止外部直接访问内部变量。保持状态: 闭包可以保持外部函数调用时的状态,例如计数器等。实现柯里化和高阶函数: 闭包支持函数式编程的概念,实现柯里化和高阶函数等功能。

缺点:

内存泄漏: 如果不适当使用,闭包可能导致内存泄漏,因为它会保留外部函数的整个作用域链。性能问题: 闭包涉及维护作用域链,可能导致性能问题,尤其是在嵌套较深的情况下。可读性降低: 过度使用闭包可能导致代码可读性降低,因为读者需要理解整个作用域链。

项目中闭包通常用于实现私有变量、保持状态或者创建工厂函数,或者防抖节流。 


点击全文阅读


本文链接:http://zhangshiyu.com/post/68308.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1