0

0

关于在JS中闭包可被利用的常见场景有哪几种?(图文教程)

亚连

亚连

发布时间:2018-05-18 16:18:24

|

1439人浏览过

|

来源于php中文网

原创

场景一:采用函数引用方式的settimeout调用

闭包的一个通常的用法是为一个在某一函数执行前先执行的函数提供参数。例如,在web环境中,一个函数作为setTimeout函数调用的第一个参数,是一种很常见的应用。

setTimeout将要执行的函数(或者一段javascript代码,但这不是我们要讨论的情况)作为它的第一个参数,下一个参数是需要延迟执行的时间。如果一段代码想通过setTimeout来调用,那么它需要传递一个函数对象的引用来作为第一个参数。延迟的毫秒数作为第二个参数,但这个函数对象的引用无法为将要被延迟执行的对象提供参数。

但是,可以调用另一个函数来返回一个内部函数的调用,将那个内部函数对象的引用传递给setTimeout函数。内部函数执行时需要的参数,在调用外部函数时传递给它。setTimeout在执行内部函数时无需传递参数,因为内部函数仍然能够访问外部函数调用时提供的参数:

function callLater(paramA, paramB, paramC) {  
            /*使用函数表达式创建并放回一个匿名内部函数的引用*/  
            return (function () {  
                /* 
                这个内部函数将被setTimeout函数执行; 
                并且当它被执行时, 
                它能够访问并操作外部函数传递过来的参数 
                */  
                paramA[paramB] = paramC;  
            });  
        }  
        /* 
        调用这个函数将在它的执行上下文中创建,并最终返回内部函数对象的引用 
        传递过来的参数,内部函数在最终被执行时,将使用外部函数的参数 
        返回的引用被赋予了一个变量 
        */  
        var funcRef = callLater(elStyle, "display", "none");  
        /*调用setTimeout函数,传递内部函数的引用作为第一个参数*/  
        hideMenu = setTimeout(funcRef, 500);

场景二:将函数关联到对象的实例方法

有很多这样的场景:需要分配一个函数对象的引用,以便在未来的某个时间执行该函数。那么闭包对于为这个将要执行的函数提供引用会非常有帮助。因为该函数可能直到执行时才能够被访问。

有一个例子就是,一个javascript对象被封装用来参与一个特定DOM元素的交互。它有doOnClick、doMouseOver以及doMouseOut方法。并且想在DOM元素上对应的事件被触发时执行这些方法。但是,可能会有关联着DOM元素的任意数量的javascript对象被创建,并且单个的实例并不知道那些实例化它们的代码将如何处理它们。对象实例不知道怎样去“全局”地引用它们自己,因为它们不知道哪个全局变量(如果存在)的引用将被分配给它们。

所以,问题是执行一个与特定javascript对象实例关联的事件处理函数,并且知道调用那个对象的哪个方法。

接下来的一个例子,在有元素事件处理的对象实例的关联函数上使用一个简单的闭包。通过传递event对象以及要关联元素的一个引用,为事件处理器分配不同的对象实例方法以供调用。

/* 
        一个给对象实例关联一个事件处理器的普通方法, 
        返回的内部函数被作为事件的处理器, 
        对象实例被作为obj参数,对象上将要被调用的方法名称被作为第二个参数 
        */  
        function associateObjWithEvent(obj, methodName) {  
            /*返回的内部函数被用来作为一个DOM元素的事件处理器*/  
            return (function (e) {  
                /* 
                事件对象在DOM标准的浏览器中将被转换为e参数, 
                如果没有传递参数给事件处理内部函数,将统一处理成IE的事件对象 
                */  
                e = e || window.event;  
                /* 
                事件处理器调用obj对象上的以methodName字符串标识的方法 
                并传递两个对象:通用的事件对象,事件处理器被订阅的元素的引用 
                这里this参数能够使用,因为内部函数已经被执行作为事件处理器所在元素的一个方法 
                */  
                return obj[methodName](e, this);  
            });  
        }  
        /* 
        这个构造器函数,通过将元素的ID作为字符串参数传递进来, 
        来创建将自身关联到DOM元素上的对象, 
        对象实例想在对应的元素触发onclick、onmouseover、onmouseout事件时 
        对应的方法被调用。 
        */  
        function DhtmlObject(elementId) {  
            /* 
            调用一个方法来获得一个DOM元素的引用 
            如果没有找到,则为null 
            */  
            var el = getElementWith(elementId);  
            /* 
            因为if语句块,el变量的值在内部进行了类型转换,变成了boolean类型 
            所以当它指向一个对象,结果就为true,如果为null则为false 
            */  
            if (el) {  
                /* 
                为了给元素指定一个事件处理函数,调用了associateObjWithEvent函数, 
                利用它自己(this关键字)作为被调用方法的对象,并且提供方法名称 
                */  
                el.onclick = associateObjWithEvent(this, "doOnClick");  
                el.onmouseover = associateObjWithEvent(this, "doOnMouseOver");  
                el.onmouseout = associateObjWithEvent(this, "doOnMouseOut");  
            }  
        }  
        DhtmlObject.prototype.doOnClick = function (event, element) {  
            //doOnClick body  
        }  
        DhtmlObject.prototype.doMouseOver = function (event, element) {  
            //doMouseOver body  
        }  
        DhtmlObject.prototype.doMouseOut = function (event, element) {  
            //doMouseOut body  
        }

任何DhtmlObject的实例都能够将它们自身关联到它们感兴趣的DOM元素上去,不需要去担心这些元素将被其他的代码怎么处理,以及被全局命名空间“污染”或者与其他的DhtmlObject的实例产生冲突。

场景三:封装相关的功能集

闭包可以创建额外的scope,这可以被用来组合相关的或有依赖性的代码。用这种方式可以最大限度地减少代码干扰的危害。假设,一个函数被用来创建一个字符串并且避免重复串联的操作(比如创建一系列的中间字符串)。一个想法是,用一个数组来顺序存储字符串的一部分,然后使用Array.prototype.join方法输出结果(使用一个空字符串作为它的参数)。数组将扮演着输出缓冲区的角色,但局部定义它又将会导致它在函数的每次执行时再次创建。如果这个数组只是作为唯一的变量被分配给每一个函数调用,这将会有点小题大做。

一个解决方案是将数组提升为全局变量,让它不需要被再次创建也能够再次使用。但结果并不是想的那么简单,另外,一个全局变量关联这使用缓冲数组的函数,那将会有第二个全局属性(函数本身也是window对象的属性)关联这个数组,这将让代码失去一定的可控性。因为如果将它使用在其他地方。这段代码的创建者不得不记住包含函数的定义以及数组的定义逻辑。它也使得代码不那么容易与其他代码整合,因为将从原来只需要确定函数名是否在全局命名空间中唯一,变成有必要确定和该函数关联的数组的名称是否在全局命名空间中保持唯一。

Interior AI
Interior AI

AI室内设计,上传室内照片自动帮你生成多种风格的室内设计图

下载

一个闭包可以让缓冲数组关联(干净地包含)它依赖的函数,并且同时保持缓冲数组的属性名称,像被分配在全局空间中一样,同时能够避免名称冲突以及代码交互干扰的危险。

这里有一招就是通过执行一个内联的函数表达式创建一个额外的执行上下文,让那个函数表达式返回一个内联的函数,该函数被外部代码使用。缓冲数组被定义在内联执行的函数表达式中,作为一个局部变量。它仅被调用一次,所以该数组只被创建一次。但是对于依赖它的函数来说该数组是一直可访问的,并且可被重用的。

接一下的代码创建了一个函数,将返回一个HTML字符串,其中的一部分是不变的,但那些不变的字符串需要被穿插进作为参数传递进来的变量中。

一个内联执行的函数表达式返回了内部函数对象的一个引用。并且分配了一个全局变量,让它可以被作为一个全局函数来调用。而缓冲数组作为一个局部变量被定义在外部函数表达式中。它没有被扩展到全局命名空间中,并且无论函数什么时候使用它都不需要被再次创建。

/* 
         定义一个全局变量:getImgInPositionedDivHtml 
         被赋予对外部函数表达式一次调用返回的一个内部函数表达式 
         内部函数返回了一个HTML字符串,代表一个绝对定位的DIV 
         包裹这一个IMG元素,而所有的变量值都被作为函数调用的参数 
*/  
        var getImgInPositionedDivHtml = (function () {  
            /* 
            buffAr 数组被定义在外部函数表达式中,作为一个局部变量 
            它只被创建一次。数组的唯一实例对内部函数是可见的, 
            所以它可以被用于每一次的内部函数执行 
            空字符串仅仅被用来作为一个占位符,它将被内部函数的参数代替 
            */  
            var buffAr = [  
                 '
@@##@@<\/div>' ]; /* 返回一个内部函数对象,他是函数表达式执行返回的结果 */ return (function (url, id, width, height, top, left, altText) { /* 分配各种参数给对应的数组元素 */ buffAr[1] = id; buffAr[3] = top; buffAr[5] = left; buffAr[13] = (buffAr[7] = width); buffAr[15] = (buffAr[9] = height); buffAr[11] = url; buffAr[17] = altText; /* 返回连接每个元素后创建的字符串 */ return buffAr.join(''); }); })();

如果一个函数依赖另一个或几个函数,但那些其他的函数并不期望与任何其他的代码产生交互。那么这个简单的技巧(使用一个对外公开的函数来扩展那些函数)就可以被用来组织那些函数。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

JS取得最小公倍数与最大公约数

JS实现数组去重算法

使用JS实现购物车功能步骤详解

关于在JS中闭包可被利用的常见场景有哪几种?(图文教程)

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

22

2026.01.27

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

119

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

48

2026.01.26

苹果官方查询网站 苹果手机正品激活查询入口
苹果官方查询网站 苹果手机正品激活查询入口

苹果官方查询网站主要通过 checkcoverage.apple.com/cn/zh/ 进行,可用于查询序列号(SN)对应的保修状态、激活日期及技术支持服务。此外,查找丢失设备请使用 iCloud.com/find,购买信息与物流可访问 Apple (中国大陆) 订单状态页面。

184

2026.01.26

npd人格什么意思 npd人格有什么特征
npd人格什么意思 npd人格有什么特征

NPD(Narcissistic Personality Disorder)即自恋型人格障碍,是一种心理健康问题,特点是极度夸大自我重要性、需要过度赞美与关注,同时极度缺乏共情能力,背后常掩藏着低自尊和不安全感,影响人际关系、工作和生活,通常在青少年时期开始显现,需由专业人士诊断。

7

2026.01.26

windows安全中心怎么关闭 windows安全中心怎么执行操作
windows安全中心怎么关闭 windows安全中心怎么执行操作

关闭Windows安全中心(Windows Defender)可通过系统设置暂时关闭,或使用组策略/注册表永久关闭。最简单的方法是:进入设置 > 隐私和安全性 > Windows安全中心 > 病毒和威胁防护 > 管理设置,将实时保护等选项关闭。

7

2026.01.26

2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】
2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】

铁路12306提供起售时间查询、起售提醒、购票预填、候补购票及误购限时免费退票五项服务,并强调官方渠道唯一性与信息安全。

178

2026.01.26

个人所得税税率表2026 个人所得税率最新税率表
个人所得税税率表2026 个人所得税率最新税率表

以工资薪金所得为例,应纳税额 = 应纳税所得额 × 税率 - 速算扣除数。应纳税所得额 = 月度收入 - 5000 元 - 专项扣除 - 专项附加扣除 - 依法确定的其他扣除。假设某员工月工资 10000 元,专项扣除 1000 元,专项附加扣除 2000 元,当月应纳税所得额为 10000 - 5000 - 1000 - 2000 = 2000 元,对应税率为 3%,速算扣除数为 0,则当月应纳税额为 2000×3% = 60 元。

39

2026.01.26

oppo云服务官网登录入口 oppo云服务登录手机版
oppo云服务官网登录入口 oppo云服务登录手机版

oppo云服务https://cloud.oppo.com/可以在云端安全存储您的照片、视频、联系人、便签等重要数据。当您的手机数据意外丢失或者需要更换手机时,可以随时将这些存储在云端的数据快速恢复到手机中。

172

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 4.2万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.5万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号