当前位置: 首页 > news >正文

【前端】JavaScript 中的函数嵌套:从基础到深度应用的全面指南


在这里插入图片描述

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳]
本文专栏: 前端

文章目录

  • 💯前言
  • 💯什么是函数嵌套
    • 示例代码
  • 💯函数嵌套的意义与优势
    • 1. 封装性与模块化
    • 2. 闭包的实现与应用
    • 3. 回调与高阶函数
    • 4. 工厂模式
  • 💯函数嵌套的不同应用场景
    • 1. 回调函数
    • 2. 闭包用于私有变量和封装
    • 3. 高阶函数中的函数嵌套
    • 4. 异步编程中的嵌套函数
  • 💯深入理解闭包与作用域链
    • 1. 作用域链的原理
    • 2. 闭包的本质与原理
  • 💯函数嵌套的实践与最佳实践
    • 1. 避免回调地狱
    • 2. 合理使用闭包
    • 3. 确保嵌套函数的职责单一
  • 💯总结


在这里插入图片描述


💯前言

JavaScript 是一门动态灵活的编程语言,被广泛应用于前端后端开发中。函数是这门语言的核心组成部分,而函数嵌套Nested Functions)是 JavaScript 中极具表现力和功能性的特性之一,广泛应用于模块化设计逻辑封装作用域管理以及高阶函数的实现。对于提升 JavaScript 编码技巧、增强代码结构的健壮性可维护性,深入理解函数嵌套至关重要。

JavaScript在这里插入图片描述


💯什么是函数嵌套

在这里插入图片描述

函数嵌套是指在一个函数的内部定义另一个函数。在 JavaScript 中,函数作为“一等公民”,可以像变量一样使用,这意味着一个函数可以在其他函数中定义和调用。函数嵌套提供了一种机制来创建封闭的作用域,使得内部函数能够访问外部函数的变量,而外部函数无法访问内部函数的变量。这种机制被广泛应用于控制数据访问权限和逻辑封装。

函数嵌套不仅有助于增强代码的结构化,还能使不同函数之间共享状态信息,形成闭包(Closure)。闭包是一种强大的 JavaScript 特性,能够在函数执行结束后依然保留对其定义时的词法环境中的变量的引用。


示例代码

在这里插入图片描述

function outerFunction(outerValue) {function innerFunction(innerValue) {return `Outer: ${outerValue}, Inner: ${innerValue}`;}return innerFunction;
}const myFunction = outerFunction("Hello");
console.log(myFunction("World")); // 输出: Outer: Hello, Inner: World

解释:

  • 在上面的例子中,outerFunction 定义了一个内部函数 innerFunction
  • innerFunction 能够访问到 outerFunction 的参数 outerValue,这种访问能力被称为闭包。
  • 调用 outerFunction 返回了 innerFunction,我们可以通过 myFunction 调用它,并传入不同的参数。

💯函数嵌套的意义与优势

在这里插入图片描述


1. 封装性与模块化

在这里插入图片描述

函数嵌套能够很好地实现代码的封装性,使内部函数的逻辑只在外部函数的范围内可用。这种封装性有助于避免命名冲突,并使得代码更易于理解和维护。通过嵌套函数,开发者可以将复杂的任务分割为多个小的模块,每个模块专注于解决具体的子问题,从而使代码更加简洁和模块化。


2. 闭包的实现与应用

在这里插入图片描述

闭包是 JavaScript 中非常重要的特性,它使得内部函数可以保持对外部函数变量的引用,即使外部函数已经执行结束。闭包能够用于创建私有变量、保持状态信息以及实现数据隐藏等功能。

function counter() {let count = 0; // 私有变量return function() {count++;return count;};
}const increment = counter();
console.log(increment()); // 输出: 1
console.log(increment()); // 输出: 2
console.log(increment()); // 输出: 3

解释:

  • counter 函数返回了一个匿名内部函数。
  • 内部函数可以访问外部函数的变量 count,形成了一个闭包,使得 countincrement 的多次调用过程中保持其状态。
  • 这种闭包机制可用于实现类似私有变量的功能,使得 count 只能通过内部函数进行访问和修改。

3. 回调与高阶函数

在这里插入图片描述

函数嵌套是实现回调函数与高阶函数的基础。高阶函数是指可以接受其他函数作为参数或者返回一个函数的函数。这种模式在 JavaScript 的异步编程中非常常见,如事件监听、Promise、以及数组的 mapfilter 等操作。

function processUserInput(input, callback) {const processed = input.trim().toUpperCase(); // 处理输入callback(processed); // 调用回调
}processUserInput("  hello world  ", function(result) {console.log(`Processed input: ${result}`); // 输出: Processed input: HELLO WORLD
});

解释:

  • processUserInput 是一个接受字符串和回调函数的高阶函数。
  • 它对输入字符串进行处理,然后调用传入的回调函数来输出处理结果。

4. 工厂模式

在这里插入图片描述

通过函数嵌套,我们可以创建函数工厂,动态生成各种函数来满足不同的需求。这种方法极大地提高了代码的可复用性。

function createMultiplier(multiplier) {return function(value) {return value * multiplier;};
}const double = createMultiplier(2);
const triple = createMultiplier(3);console.log(double(5)); // 输出: 10
console.log(triple(5)); // 输出: 15

解释:

  • createMultiplier 是一个工厂函数,用于生成乘法器函数。
  • 调用 createMultiplier(2) 生成了一个 double 函数,作用是将输入的数乘以 2。通过函数嵌套可以实现灵活的函数生成机制,适应不同应用场景的需求。

💯函数嵌套的不同应用场景

在这里插入图片描述


1. 回调函数

在这里插入图片描述

JavaScript 中回调函数是函数嵌套最常见的应用之一,特别是在异步编程中,比如处理用户事件、读写文件、网络请求等。

例如,当用户点击按钮时执行的代码通常是通过回调函数定义的:

document.getElementById("myButton").addEventListener("click", function() {console.log("Button clicked!");
});

解释:

  • addEventListener 接受一个回调函数作为参数,当用户点击按钮时执行该回调。
  • 这个匿名函数作为回调函数被嵌套在 addEventListener 中。

2. 闭包用于私有变量和封装

在这里插入图片描述

闭包是函数嵌套的另一个应用,通过闭包可以隐藏一些数据,仅允许通过内部函数访问,从而实现数据封装。

function secretHolder() {let secret = "I love JavaScript!";return {getSecret: function() {return secret;},setSecret: function(newSecret) {secret = newSecret;}};
}const mySecret = secretHolder();
console.log(mySecret.getSecret()); // 输出: I love JavaScript!
mySecret.setSecret("JavaScript is awesome!");
console.log(mySecret.getSecret()); // 输出: JavaScript is awesome!

解释:

  • secretHolder 函数返回了一个对象,该对象包含两个方法:getSecretsetSecret
  • secret 变量在 secretHolder 作用域内是私有的,只能通过 getSecretsetSecret 进行访问和修改。

3. 高阶函数中的函数嵌套

在这里插入图片描述

高阶函数是指接受函数作为参数,或者返回一个函数的函数。通过函数嵌套可以方便地实现高阶函数,使代码更加灵活。

function mapArray(arr, transform) {const result = [];for (let item of arr) {result.push(transform(item)); // 调用传入的回调函数}return result;
}const numbers = [1, 2, 3, 4];
const squares = mapArray(numbers, x => x * x);
console.log(squares); // 输出: [1, 4, 9, 16]

解释:

  • mapArray 是一个高阶函数,它接受一个数组和一个函数 transform 作为参数。
  • 它将 transform 应用于数组中的每一个元素,生成新的数组。

4. 异步编程中的嵌套函数

在这里插入图片描述

在 JavaScript 中,异步编程是实现非阻塞操作的关键,函数嵌套在处理异步任务时非常普遍。例如通过 setTimeoutPromise、或 async/await

function fetchData(url, callback) {setTimeout(() => {const data = `Data from ${url}`;callback(data); // 模拟异步回调}, 1000);
}fetchData("https://api.example.com", function(data) {console.log(data); // 输出: Data from https://api.example.com
});

或者使用 async/await 的方式:

async function fetchData() {return new Promise(resolve => {setTimeout(() => resolve("Data fetched!"), 1000);});
}async function main() {const result = await fetchData();console.log(result); // 输出: Data fetched!
}main();

解释:

  • 上面的例子使用 async/await,使代码结构更加直观,避免了回调函数的层层嵌套(即 “回调地狱”)。

💯深入理解闭包与作用域链

在这里插入图片描述


1. 作用域链的原理

在这里插入图片描述

当函数被嵌套时,JavaScript 通过作用域链来管理变量的访问权限。作用域链是一种类似链表的数据结构,保存了当前执行上下文以及其父上下文中的变量。

在一个嵌套函数中,如果查找一个变量,JavaScript 引擎会从最内层函数开始查找,如果找不到就逐层向外查找,直到找到变量或者到达全局作用域。

function outerFunction() {let outerVar = "Outer";function innerFunction() {console.log(outerVar); // 能够访问到外部函数的变量}innerFunction();
}outerFunction(); // 输出: Outer

解释:

  • innerFunction 中,JavaScript 引擎首先查找内部是否有 outerVar 变量。
  • 如果找不到,就沿作用域链向上查找,最终找到 outerVar,因此能够成功打印出它的值。

2. 闭包的本质与原理

在这里插入图片描述

闭包是函数嵌套的一个重要副产品。闭包是指函数和其词法环境的组合,意味着函数不仅包括它的代码逻辑,还包括了创建它时的外部作用域。

闭包使得我们可以保持对外部作用域变量的引用,即使外部函数已经执行结束。

function createCounter() {let count = 0;return function() {count++;return count;};
}const counter1 = createCounter();
console.log(counter1()); // 输出: 1
console.log(counter1()); // 输出: 2

解释:

  • 当调用 createCounter 时,返回的内部函数被赋值给 counter1
  • 虽然 createCounter 执行完毕,但因为闭包的存在,count 变量仍然保留在内存中,counter1 函数可以继续访问和修改 count

💯函数嵌套的实践与最佳实践

在这里插入图片描述


1. 避免回调地狱

在这里插入图片描述

回调函数是 JavaScript 异步编程的核心,但层层嵌套的回调容易导致代码难以阅读和维护,这种现象被称为 “回调地狱”。为了解决这一问题,开发者可以使用以下几种方法:

  • 使用 Promise:将回调封装到 Promise 中,避免深层嵌套。

    function fetchData(url) {return new Promise((resolve, reject) => {setTimeout(() => resolve(`Data from ${url}`), 1000);});
    }fetchData("https://api.example.com").then(data => {console.log(data);}).catch(error => {console.error("Error:", error);});
    
  • 使用 async/await:async/await 使得异步代码看起来更加线性化,容易理解。

    async function main() {try {const data = await fetchData("https://api.example.com");console.log(data);} catch (error) {console.error("Error:", error);}
    }main();
    

2. 合理使用闭包

在这里插入图片描述

闭包可以用于数据的封装和模块化,但也可能引起内存泄漏,尤其是在创建了大量不必要的闭包时。因此,在实际开发中应尽量避免无意义的嵌套和使用闭包。


3. 确保嵌套函数的职责单一

在这里插入图片描述

每个嵌套函数应具有单一的功能,这样可以保证代码的可维护性。当函数的逻辑变得复杂时,可以考虑将其拆分为多个嵌套函数,以保证每个函数的代码量适中。


💯总结

  • 在这里插入图片描述
    JavaScript 中的函数嵌套是一个功能强大灵活的特性,广泛应用于实现闭包、模块化、高阶函数和异步编程。通过嵌套函数,可以有效地封装逻辑、保护变量、保持状态以及实现复杂的功能。

  • 函数嵌套可以通过封装和作用域控制,使代码更加简洁模块化

  • 闭包是函数嵌套的重要产物之一,能够保持对外部函数变量的引用,实现状态的保持

  • 异步编程中,函数嵌套和回调函数的应用尤其广泛,但为了避免回调地狱,应当使用 Promiseasync/await 等手段进行优化。

通过学习和掌握函数嵌套,我们可以更好地编写可维护、可扩展的 JavaScript 代码,使代码逻辑更加清晰,从而更好地满足实际应用的需求。希望这篇文章能够帮助您深入理解函数嵌套,并在实践中灵活运用这一强大的工具。


在这里插入图片描述


相关文章:

【前端】JavaScript 中的函数嵌套:从基础到深度应用的全面指南

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 💯前言💯什么是函数嵌套示例代码 💯函数嵌套的意义与优势1. 封装性与模块化2. 闭包的实现与应用3. 回调与高阶函数4. 工厂模式 💯函数嵌套的不同应用场景…...

微信小程序条件渲染与列表渲染的全面教程

微信小程序条件渲染与列表渲染的全面教程 引言 在微信小程序的开发中,条件渲染和列表渲染是构建动态用户界面的重要技术。通过条件渲染,我们可以根据不同的状态展示不同的内容,而列表渲染则使得我们能够高效地展示一组数据。本文将详细讲解这两种渲染方式的用法,结合实例…...

全面击破工程级复杂缓存难题

目录 一、走进业务中的缓存 (一)本地缓存 (二)分布式缓存 二、缓存更新模式分析 (一)Cache Aside Pattern(旁路缓存模式) 读操作流程 写操作流程 流程问题思考 问题1&#…...

python安装包中的一些问题(三):加载 matplotlib 的过程中,调用了 Pillow(PIL 库)时发生了错误

报错: runfile(/Volumes/Expansion/Stuttgart/code_run/glacier_map_hugonnet/test_image_cut.py, wdir/Volumes/Expansion/Stuttgart/code_run/glacier_map_hugonnet) Traceback (most recent call last): File /opt/anaconda3/lib/python3.11/site-packages/spyd…...

AWTK-WEB 快速入门(1) - C 语言应用程序

先安装 AWTK Designer 用 AWTK Designer 新建一个应用程序 2.1. 新建应用程序 这里假设应用程序的名称为 AwtkApplicationC,后面会用到,如果使用其它名称,后面要做相应修改。 在窗口上放置一个按钮将按钮的名称改为 “close”将按钮的文本改…...

【Spiffo】环境配置:VScode+Windows开发环境

摘要: 在Linux下直接开发有时候不习惯快捷键和操作逻辑,用Windows的话其插件和工具都更齐全、方便,所以配置一个Windows的开发环境能一定程度提升效率。 思路: 自己本地网络内远程连接自己的虚拟机(假定用的是虚拟机…...

贴代码框架PasteForm特性介绍之file

简介 PasteForm是贴代码推出的 “新一代CRUD” ,基于ABPvNext,目的是通过对Dto的特性的标注,从而实现管理端的统一UI,借助于配套的PasteBuilder代码生成器,你可以快速的为自己的项目构建后台管理端!目前管…...

2024年 数模美赛 B题 潜水艇

摘要 随着深海探险活动的增加,确保潜水器及其乘客的安全成为一项重要任务。本文旨在为Maritime Cruises Mini-Submarines (MCMS)公司开发一套模型,用于预测潜水艇在发生故障时的位置,并制定有效的搜救策略。本文将详细讨论模型的开发、不确定…...

ChatGPT 与其他 AI 技术在短视频营销中的技术应用与协同策略

摘要: 本文深入探讨了 ChatGPT 及其他 AI 技术在短视频营销中的应用。从技术层面剖析了这些技术如何助力短视频内容创作、个性化推荐、用户互动以及营销效果评估等多方面,通过具体方法分析、数据引用与大模型工具介绍,旨在为短视频营销领域提…...

H.265流媒体播放器EasyPlayer.js播放器提示MSE不支持H.265解码可能的原因

随着人工智能和机器学习技术的应用,流媒体播放器将变得更加智能,能够根据用户行为和偏好提供个性化的内容推荐。总体而言,流媒体播放器的未来发展将更加注重技术创新和用户互动,以适应不断变化的市场需求和技术进步。 提示MSE不支…...

电脑自动关机时间如何定?Wise Auto Shutdown 设置关机教程

在日常使用电脑的过程中,有时我们需要让电脑在特定的时间自动关机,比如在下载大文件完成后、执行长时间的任务结束时,或者只是单纯想在某个预定时间让电脑自动关闭以节省能源。这时候,Wise Auto Shutdown 这款软件就能派上大用场了…...

笔记mfc11

Subclass(子类化)是MFC中最常用的窗体技术之一。子类化完成两个工作:一是把窗体类对象attach到一个windows窗体实体中(即把一个窗体的hwnd赋给该类)。另外就是把该类对象的消息加入到消息路由中,使得该类可以捕获消息。 让edit能…...

【探寻密码的奥秘】-001:解开密码的神秘面纱

目录 1、密码学概述1.1、概念1.2、目的1.3、应用场景 2、密码学的历史2.1、第一时期:古代密码时代2.2、第二时期:机械密码时代2.3、第三时期:信息密码时代2.4、第四时期:现代密码时代 3、密码学的基本概念3.1、一般通信系统3.2、保…...

ElasticSearch7.x入门教程之集群安装(一)

文章目录 前言一、es7.x版本集群安装二、elasticsearch-head安装三、Kibana安装总结 前言 在工作中遇到了,便在此记录一下,以防后面会再次遇到。第一次使用是在2020年末,过了很久了,忘了些许部分了。 在工作当中,如果…...

c++ 笔记

基础知识 1. 指针、引用2. 数组3. 缺省参数4. 函数重载5. 内联函数6. 宏7. auto8. const9. 类和对象10. 类的6个默认成员函数11. 初始化列表12. this指针13. C/C的区别14. C 三大特性15. 结构体内存对齐规则16. explicit17. static18. 友元类、友元函数19. 内部类20. 内存管理&…...

【腾讯云】AI驱动TDSQL-C Serveress 数据库技术实战营-如何是从0到1体验电商可视化分析小助手得统计功能,一句话就能输出目标统计图

欢迎来到《小5讲堂》 这是《腾讯云》系列文章,每篇文章将以博主理解的角度展开讲解。 温馨提示:博主能力有限,理解水平有限,若有不对之处望指正! 目录 背景效果图流程图创建数据库基本信息数据库配置设置密码控制台开启…...

10 —— Webpack打包模式

开发模式:development ;场景:本地开发 生产模式:production ; 场景:打包上线 设置: 方式1.webpack.config.js 配置文件设置mode选项 module.exports { mode:production }; 方式2.在packa…...

【ArcGIS微课1000例】0132:从多个GIS视角认识与攀登珠穆朗玛峰

文章目录 1. Map Viewer中打开2. 场景查看器中打开3. ArcGIS中打开4. QGIS中打开5. Globalmapper中打开6. ArcGIS Earth中打开官网地址:https://www.arcgis.com/home/item.html?id=504a23373ab84536b7760c0add1e0c1c 1. Map Viewer中打开 以下展示不同底图样式的珠穆朗玛峰壮…...

vue2 - 20.json-server

json-server 目标:基于 json-server 工具,准备后端接口服务环境 1. 安装全局工具 json-server (全局工具仅需要安装一次)【官网】 yarn global add json-server 或 npm i json-server -g yarn global add json-server npm i …...

echarts4r 教程1:Get Started

❝ 写在前面 本文为 R 语言 echarts4r 包的学习笔记。本着自己学习、分享他人的态度,分享学习笔记,希望能对大家有所帮助。软件可能随时更新,建议配合官方文档一起阅读。 目录 1 Video & Article 2 Your first plot 3 Options 4 Navigate…...

蚁群算法(Ant Colony Optimization, ACO)

简介 蚁群算法(Ant Colony Optimization, ACO)是一种基于自然启发的优化算法,由意大利学者马可多里戈(Marco Dorigo)在1992年首次提出。它受自然界中蚂蚁觅食行为的启发,用于解决离散优化问题。 在自然界…...

使用IDEA构建springboot项目+整合Mybatis

目录 目录 1.Springboot简介 2.SpringBoot的工作流程 3.SpringBoot框架的搭建和配置 4.用Springboot实现一个基本的select操作 5.SpringBoot项目部署非常简单,springBoot内嵌了 Tomcat、Jetty、Undertow 三种容器,其默认嵌入的容器是 Tomcat,…...

苹果系统中利用活动监视器来终止进程

前言 苹果系统使用的时候总是感觉不太顺手。特别是转圈的彩虹球出现的时候,就非常令人恼火。如何找到一个像Windows那样任务管理器来终止掉进程呢? 解决办法 Commandspace 弹出搜索框吗,如下图: 输入“活动”进行搜索&#xff…...

宝塔安装雷池网站防护

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、 加载镜像二、使用步骤三、如果启动不成三、 启动成功以后三、 进入雷池不知道密码 前言 提示:这里可以添加本文要记录的大概内容:…...

JavaScript完整原型链

在 JavaScript 中,每个函数都有一个prototype属性,这个属性是一个对象。当通过一个构造函数创建一个新的对象时,这个新对象会自动拥有一个内部属性[[Prototype]](在一些浏览器中可以通过__proto__访问,不过这是一个非标…...

Vue 内置组件 keep-alive 中 LRU 缓存淘汰策略和实现

LRU(Least Recently Used,最近最少使用)是通过记录缓存项的访问顺序来决定淘汰的策略:当缓存满时,移除最久未被使用的项。 核心概念: 缓存存储:使用 Map 存储键值对,用于快速访问缓…...

李宏毅机器学习课程知识点摘要(14-18集)

线性回归,逻辑回归(线性回归sigmoid),神经网络 linear regression , logistic regression , neutral network 里面的偏导的相量有几百万维,这就是neutral network的不同,他是…...

《AI大模型开发笔记》Faster-Whisper 免费开源的高性能语音识别模型

1 Whisper模型,免费开源的语音识别模型 Whisper模型是OpenAI公开的语音识别模型。这是一个免费可商用的模型。 Whisper模型根据参数量来区分,有多个不同的版本,分别是tiny,base,small medium,large&#x…...

蓝队基础,网络七杀伤链详解

声明! 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&#…...

golang开发一个海盗王的登录更新器

前段时间,用golang配合界面库govcl开发一个海盗王的登陆更新器,实现多区注册和文件更新分离不同服务器等新功能。 由于govcl没有更换皮肤的功能,界面都是默认,不好看。 找了很多go语言的gui库,都没有符合要求的。 后来…...