一起认识闭包

一起认识闭包

相关学习推荐:javascript视频教程

前言

闭包 永远都是前端开发者绕不过去的一个坎,不管你喜欢与否,在工作和面试中,都会遇到。每个人对闭包的理解都不尽相同,这里笔者谈谈自身对闭包的理解。(如果与您的理解有出入,请以您自己为准  )

如何定义闭包

在给出定义之前,不妨看看别人是如何定义闭包的:

函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中称为“闭包” — JavaScript权威指南(第六版)

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。 — JavaScript高级程序设计(第三版)

当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。 — 你不知道的JavaScript(上卷)

虽然上面的几段话描述起来并不一样,但是您细细品味后还是能找出一些共同点。其中最重要的是不同作用域之间的联系。当然了,您可以直接引用上面的定义(毕竟上面几个定义还是比较权威的),这里笔者比较喜欢最后一段的定义,同时力推《你不知道的JavaScript(上卷)》这本书,值得反复细读。

闭包涉及哪些知识点

光给出定义是远远不够的,还必须探讨内部涉及了哪些知识点。下面是笔者认为有用到的知识点。

作用域与作用域链

嗯,其实笔者知道你们都想到了这点(不会吧,不会有人没想到这点吧)。既然大家都了解作用域。这里就简单描述一下,过一下场即可。

作用域:根据名称查找变量的一套规则。分为三种类型:全局作用域;函数作用域;块作用域。

需要注意的是块作用域,ES6新增的规范。 在花括号{}里面使用let,const定义的变量,都会绑定到该作用范围内,花括号以外的地方无法访问。注意:在花括号开始 到 let变量声明之前,存在暂时性死区(该点不在本文讨论范围)。

作用域链:当不同的作用域 (混~淆~在~一~起~ 呸,不小心出戏了) 圈套在一起时,就形成了作用域链。注意的是,查找方向是从内到外的。

为什么作用域的查找方向是从内到外的呢?这是个很有趣的问题。个人觉得是跟js执行函数的入栈方式决定的(感觉有点偏题了,有兴趣的小伙伴可以去查一下资料)。

词法作用域

函数之所以 可以访问另一个函数作用域的变量(或者说记住当前的作用域并在当前以外的地方访问)的关键点就是词法作用域在起作用。这一点很重要,但不是所有人都知道这个知识点,这里简单探讨一下。

在编程界中,存在两种作用域工作模式,一种是被大多数编程语言所采用的词法作用域;另一种就是与其相反的动态作用域(这个不在本文的讨论范围)。

词法作用域: 变量和块的作用域 在 您编写代码的阶段 就已经确定好了,不会随着调用的对象或者地方的不同而改变(感觉跟this相反)。

要不,举个栗子看看吧:

let a = 1;function fn(){    let a = 2;    function fn2(){        console.log(a);    } return fn2;}let fn3 = fn();fn3();

登录后复制

从上面的定义可以知道,fn是一个闭包函数,fn3拿到了fn2的指针地址,当fn3执行的时候,其实是执行fn2,而里面的a变量,根据作用域链的查找规则,找到的是fn作用域内的变量a,所以最终的输出是2,不是1。(可以看下图)

一起认识闭包

题外话,如何欺骗词法作用域?

虽然词法作用域是静态的,但依然有办法可以欺骗它,达到动态的效果。

第一种方法是使用eval. eval可以把字符串解析成一个脚本来运行,由于在词法分析阶段,无法预测eval运行的脚本,所以不会对其进行优化分析。

第二种方法是with. with通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。with本身比较难掌握,使用不当容易出现意外情况(如下例子),不推荐使用 -.-

function Fn(obj){    with(obj){        a = 2;    }}var o1 = {    a:1}var o2 = {    b:1}Fn(o1);console.log(o1.a); //2Fn(o2);console.log(o2.a); //undefined;console.log(a); //2 a被泄漏到全局里面去了// 这是with的一个副作用, 如果当前词法作用域没有该属性,会在全局创建一个

登录后复制

闭包能干啥?

闭包的使用场景可多了,平时使用的插件或者框架,基本上都有闭包的身影,可能您没留意过罢了。下面笔者列举一些比较常见的场景。

模拟私有变量和方法,进一步来说可以是模拟模块化;目前常用的AMD,CommonJS等模块规范,都是利用闭包的思想;

柯里化函数或者偏函数;利用闭包可以把参数分成多次传参。如下面代码:

// 柯里化函数function currying(fn){    var allArgs = [];    function bindCurry(){        var args = [].slice.call(arguments);        allArgs = allArgs.concat(args);        return bindCurry;    }    bindCurry.toString = function(){        return fn.apply(null, allArgs);    };    return bindCurry;}

登录后复制

实现防抖或者节流函数;

实现缓存结果(记忆化)的辅助函数:

// 该方法适合缓存结果不易改变的函数const memorize = fn => {    let memorized = false;    let result = undefined;    return (...args) => {        if (memorized) {            return result;        } else {            result = fn.apply(null,args);             memorized = true;            fn = undefined;            return result;        }    };};

登录后复制

如何区分闭包?

说了那么多,我怎么知道自己写的代码是不是闭包呢?先不说新手,有些代码的确隐藏的深,老鸟不仔细看也可能发现不了。那有没有方法可以帮助我们区分一个函数是不是闭包呢?答案是肯定的,要学会善于利用周边的工具资源,比如浏览器。

打开常用的浏览器(chrome或者其他),在要验证的代码中打上debugger断点,然后看控制台,在scope里面的Closure(闭包)里面是否有该函数(如下图)。

一起认识闭包

闭包真的会导致内存泄漏?

答案是有可能。内存泄漏的原因在于垃圾回收(GC)无法释放变量的内存,导致运行一段时候后,可用内存越来越少,最终出现内存泄漏的情况。常见的内存泄漏场景有4种:全局变量;闭包引用;DOM事件绑定;不合理使用缓存。其中,闭包导致内存泄漏都是比较隐蔽的,用肉眼查看代码判断是比较难,我们可用借助chrome浏览器的Memory标签栏工具来调试。由于篇幅问题,不展开说明了,有兴趣自己去了解一下如何使用。

想了解更多编程学习,敬请关注php培训栏目!

以上就是一起认识闭包的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2725833.html

(0)
上一篇 2025年3月7日 23:26:43
下一篇 2025年3月1日 01:16:23

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 一张纸搞懂JS系列(3)之垃圾回收机制,内存泄漏,闭包

    javascript栏目为大家介绍垃圾回收机制,内存泄漏,闭包的内容,快端小板凳来看看啦。 写在最前面:这是javascript栏目我即将开始写的一个系列,主要是在框架横行的时代,虽然上班用的是框架,但是对于面试,以及技术进阶,JS基础知识…

    2025年3月7日
    200
  • JavaScript 来好好盘一盘闭包!

    今天JavaScript栏目好好介绍闭包。 前言 想要深入学习JavaScript这门语言,闭包这个概念几乎是绕不开的关键,今天就让我们一起好好地盘一盘,闭包到底是什么东西。如果是零基础的小伙伴,可以先看看前一篇文章,帮助你更好的理解本文的…

    2025年3月7日
    200
  • 介绍JavaScript作用域和闭包

    免费学习推荐:javascript视频教程 JavaScript作用域和闭包 在javascript中,如果对作用域和闭包弄不清楚,写代码就会出很多问题,今天对作用域和闭包做一个总结。 作用域 立即学习“Java免费学习笔记(深入)”; 作…

    2025年3月7日
    200
  • 理解Javascript中的Closure(闭包)

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。 一、变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域。 变量的作用域无非就是两种:全局变量和局部变量。 立即…

    2025年3月7日
    200
  • 7个JavaScript中关于闭包的面试题,你能回答上来吗?

    相关推荐:2021年大前端面试题汇总(收藏) 每个 JavaScript 程序员都必须知道闭包是什么。在 JavaScript 面试中,你很可能会被问到闭包的概念。 以下是 7 个有关 JavaScript 闭包的面试题,比较有挑战性。 不…

    2025年3月7日
    200
  • 什么是闭包?聊聊javascript中闭包,看看闭包有哪些作用?

    什么是闭包?看看闭包有哪些作用?下面本篇文章带大家聊聊javascript中闭包。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 在前端学习的过程中,我们难免会遇到许许多多的问题,那么今天我们来以一个初学者的角度来谈谈两个…

    2025年3月7日
    200
  • 一文详解JavaScript中的闭包

    javascript 闭包是一种重要的概念,在 javascript 编程中被广泛使用。尽管它可能会让初学者感到困惑,但它是理解 javascript 语言核心的关键概念之一。本文将深入探讨 javascript 闭包,让你了解它是如何工作…

    2025年3月7日
    200
  • 理解JavaScript闭包的基本原理

    javascript的闭包是一个相对复杂的概念。许多初学者都会在了解闭包之前觉得有些困难,但对于深入了解javascript和编写高质量代码来说,闭包是一个重要的概念。 什么是闭包?闭包是指一个函数可以访问其作用域之外的变量,即使在函数外部…

    编程技术 2025年3月7日
    200
  • 闭包引起的内存泄漏有哪些

    闭包引起的内存泄漏有:1、无限循环和递归调用;2、闭包内部引用了全局变量;3、闭包内部引用了不可清理的对象。详细介绍:1、无限循环和递归调用,当一个闭包在内部引用外部的变量,并且这个闭包又被外部的代码反复调用时,就可能导致内存泄漏,这是因为…

    2025年3月7日
    200
  • 解决闭包引发的内存泄漏问题的探究与解决方法

    闭包引起的内存泄漏是一种在编程中常见的问题。本文将深入探讨闭包引起内存泄漏的原因,并介绍一些解决方案。同时,将提供具体的代码示例,以便更好地理解和应用。 首先,让我们明确闭包是什么。闭包是指一个函数能够访问和操作其外部函数中定义的变量。当一…

    2025年3月7日
    200

发表回复

登录后才能评论