前端百题斩【013】——用“闭包”问题征服面试官

简介: 前端百题斩【013】——用“闭包”问题征服面试官

640.jpg

13.1 定义


在JavaScript中,根据词法作用域的规则,内部函数总是可以访问其外部函数声明的变量,当通过调用一个外部函数返回一个内部函数后,即使该外部函数已经执行结束了,但是内部函数引用外部函数的变量依然保存在内存中,就把这些变量的集合称为闭包。


13.2 闭包实现


在一个函数中嵌套另一个函数或者将一个匿名函数作为值传入另一个函数中。


// 函数fun1中嵌套了fun2,fun2作为参数返回,外部调用时仍能打印val1,构成闭包
function fun1() {
    const val1 = 10;
    function fun2() {
        console.log(val1);
    }
    return fun2;
}
function fun3() {
    const val2 = 20;
    // 定时器中的为一个匿名函数,其作为参数传入了,函数fun3执行完毕之后,1s钟后才会执行定时器函数,但此时还能打印val2,构成闭包
    setTimeout(function() {
        console.log(val2);
    }, 1000);
}

13.3 流程


根据下面的函数来看看闭包的整个执行流程


function main() {
    const val1 = 20;
    var val2 = 2
    function valResult() {
        return val1 * val2;
    }
    return valResult;
}
var result = main();
console.log(result()); // 40


640.png

640.png

640.png


上图中展示了各个时期的调用栈,需要重点关注以下几点:


  1. 当main函数执行完毕后,main函数的执行上下文从栈顶弹出;
  2. 返回的方法(valResult)中调用了main函数中的val1和val2变量,这两个变量就会打包成closure闭包,加到[[scopes]];
  3. 调用返回的方法时,作用域链为:result函数作用域——Closure(main)——全局作用域


13.4 优缺点


  1. 优点


(1)可以重复使用变量,并且不会造成变量污染;
(2)可以用来定义私有属性和私有方法


  1. 缺点


(1)会产生不销毁的上下文,导致栈/堆内存消耗过大
(2)会造成内存泄露。


扩展:闭包是怎么回收的?


  1. 如果闭包引入的函数是一个全局变量,那么闭包会一直存在直到页面关闭;但如果这个闭包以后不再使用的话,就会造成内存泄露;


  1. 如果引用闭包的函数是一个局部变量,等函数销毁后,在下次JavaScript引擎执行垃圾回收时,判断闭包内容已经不再被使用,则js引擎的垃圾回收器就会进行回收。

13.5 用途


闭包用途主要有以下两个:


  1. 创建私有变量


function MyName(name) {
    return {
        getName() {
            return name;
        }
    }
}
const myName = MyName('lili');
// 只能通过getName访问对应的名字,别的方式访问不到
console.log(myName.getName()); // lili
  1. 作为回调函数。当把函数作为值传递到某处,并在某个时刻进行回调的时候就会创建一个闭包。例如定时器、DOM事件监听器、Ajax请求。


function fun(name) {
    setTimeout(() => {
        console.log(name);
    }, 1000);
}
fun('linlin');

13.6 经典闭包问题


多个子函数的[[scope]]都是同时指向父级,是完全共享的。因此当父级的变量对象被修改时,所有子函数都受到影响。


for (var i = 1; i < 5; i++) {
    setTimeout(() => console.log(i), 1000);
}

上述代码本意是输出1、2、3、4,但结果却是四个5,为了解决该问题,主要有三种办法。


  1. 变量可以通过 函数参数的形式 传入,避免使用默认的[[scope]]向上查找


for (var i = 1; i < 5; i++) {
    (function(i) {
        setTimeout(() => console.log(i), 1000);
    })(i);
}
  1. 使用setTimeout包裹,通过第三个参数传入。(注:setTimeout后面可以有多个参数,从第三个参数开始其就作为回掉函数的附加参数)


for (var i = 1; i < 5; i++) {
    setTimeout(value => console.log(value), 1000, i);
}
  1. 使用 块级作用域,让变量成为自己上下文的属性,避免共享


for (let i = 1; i < 5; i++) {
    setTimeout(() => console.log(i), 1000);
}


相关文章
|
自然语言处理 JavaScript 前端开发
当面试官再问我JS闭包时,我能答出来的都在这里了。
闭包(Closure)是前端面试中的高频考点,广泛应用于函数式编程中。它不仅指函数内部定义的函数,还涉及内存管理、作用域链和垃圾回收机制。闭包可以让函数访问其外部作用域的变量,但也可能引发内存泄漏等问题。通过合理使用闭包,可以实现模块化、高阶函数和回调函数等应用场景。然而,滥用闭包可能导致代码复杂度增加、调试困难以及潜在的性能问题。为了避免这些问题,开发时应谨慎处理闭包,避免不必要的嵌套,并及时清理不再使用的变量和监听器。
515 16
当面试官再问我JS闭包时,我能答出来的都在这里了。
|
存储 JavaScript 前端开发
2022年前端js面试题
2022年前端js面试题
515 156
|
存储 XML 移动开发
前端大厂面试真题
前端大厂面试真题
|
Web App开发 前端开发 Linux
「offer来了」浅谈前端面试中开发环境常考知识点
该文章归纳了前端开发环境中常见的面试知识点,特别是围绕Git的使用进行了详细介绍,包括Git的基本概念、常用命令以及在团队协作中的最佳实践,同时还涉及了Chrome调试工具和Linux命令行的基础操作。
「offer来了」浅谈前端面试中开发环境常考知识点
|
缓存 前端开发 JavaScript
"面试通关秘籍:深度解析浏览器面试必考问题,从重绘回流到事件委托,让你一举拿下前端 Offer!"
【10月更文挑战第23天】在前端开发面试中,浏览器相关知识是必考内容。本文总结了四个常见问题:浏览器渲染机制、重绘与回流、性能优化及事件委托。通过具体示例和对比分析,帮助求职者更好地理解和准备面试。掌握这些知识点,有助于提升面试表现和实际工作能力。
328 1
|
存储 前端开发 JavaScript
前端必备知识:闭包的概念、作用与应用
前端必备知识:闭包的概念、作用与应用
347 1
|
存储 JavaScript 前端开发
|
存储 前端开发 JavaScript
44 个 React 前端面试问题
【8月更文挑战第18天】
335 2
|
Web App开发 JavaScript 前端开发
前端Node.js面试题
前端Node.js面试题
|
存储 前端开发 JavaScript
44 个 React 前端面试问题
44 个 React 前端面试问题

热门文章

最新文章

  • 1
    前端如何存储数据:Cookie、LocalStorage 与 SessionStorage 全面解析
    874
  • 2
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(九):强势分析Animation动画各类参数;从播放时间、播放方式、播放次数、播放方向、播放状态等多个方面,完全了解CSS3 Animation
    401
  • 3
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(八):学习transition过渡属性;本文学习property模拟、duration过渡时间指定、delay时间延迟 等多个参数
    305
  • 4
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(七):学习ransform属性;本文学习 rotate旋转、scale缩放、skew扭曲、tanslate移动、matrix矩阵 多个参数
    271
  • 5
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(六):全方面分析css的Flex布局,从纵、横两个坐标开始进行居中、两端等元素分布模式;刨析元素间隔、排序模式等
    399
  • 6
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(五):背景属性;float浮动和position定位;详细分析相对、绝对、固定三种定位方式;使用浮动并清除浮动副作用
    582
  • 7
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(四):元素盒子模型;详细分析边框属性、盒子外边距
    609
  • 8
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(三):元素继承关系、层叠样式规则、字体属性、文本属性;针对字体和文本作样式修改
    186
  • 9
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(二):CSS伪类:UI伪类、结构化伪类;通过伪类获得子元素的第n个元素;创建一个伪元素展示在页面中;获得最后一个元素;处理聚焦元素的样式
    527
  • 10
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(一):CSS发展史;CSS样式表的引入;CSS选择器使用,附带案例介绍
    343