ES6进阶知识二

一、promise方法的案例

Promise对象通过new Promise()语法创建,它接受一个函数作为参数,该函数接受两个参数:resolve和reject。resolve表示异步操作成功,reject表示异步操作失败。

案例:异步加载图片

const loadImage = (url) => {return new Promise((resolve, reject) => {const img = new Image();img.onload = () => {resolve(img);};img.onerror = () => {reject(new Error(`Failed to load image from ${url}`));};img.src = url;});
};loadImage('https://example.com/image.jpg').then((img) => {console.log('Image loaded successfully');document.body.appendChild(img);}).catch((error) => {console.error(error.message);});

Promise.prototype.then()

then()方法接受两个可选参数:onFulfilled和onRejected,分别表示成功时和失败时的回调函数。当Promise对象的状态为fulfilled时,会立即执行onFulfilled回调函数,并将操作结果作为参数传递给该函数;当Promise对象的状态为rejected时,会立即执行onRejected回调函数,并将拒绝原因(错误信息)作为参数传递给该函数。

案例

const p = new Promise((resolve, reject) => {resolve(1);
});p.then((res) => {console.log(res); // 输出:1return 2; // 返回值会被作为下一个then的输入},(error) => {console.log(error);}
)
.then((res) => {console.log(res); // 输出:2}
);

Promise.prototype.catch()

catch()方法是then(undefined, onRejected)的语法糖,用于捕获Promise对象被rejected时的错误信息。

案例

const p = new Promise((resolve, reject) => {reject('error');
});p.then((res) => {console.log(res); // 不会执行
})
.catch((error) => {console.log(error); // 输出:error
});

1.1.promise.all

过程:

1.创建promise数组:首先,需要创建一个包含多个promise对象的数组,每个promise对象都代表一个异步操作。

2.调用promise.all:然后调用promise.all方法,并将这个数组作为参数传递给它。promise.all会返回一个新的promise对象

3.处理结果:

如果所有的输入promiase对象都成功解析,那么promise.all返回的promise对象也会被解析,并且它的解析值是一个数组,包含了所有输入promise对象的解析值,顺序与输入数组一致。

如果任何一个输入promise对象被拒绝,那么promise.all返回的promise对象也会被拒绝,并且它的拒绝原因与第一个被拒绝的promise对象的拒绝原因相同。

4.使用.then和.catch:可以使用.then方法来处理成功的情况,使用.catch方法来处理失败的情况

例子:同时加载多张图片

const urls = ['https://example.com/image1.jpg','https://example.com/image2.jpg','https://example.com/image3.jpg'
];const loadImage = (url) => {return new Promise((resolve, reject) => {const img = new Image();img.onload = () => {resolve(img);};img.onerror = () => {reject(new Error(`Failed to load image from ${url}`));};img.src = url;});
};Promise.all(urls.map(loadImage)).then((images) => {console.log('All images loaded successfully');images.forEach((img) => {document.body.appendChild(img);});}).catch((error) => {console.error(error.message);});

1.2.promise.race

过程:

1.创建promise数组:首先,需要创建一个包含多个promise对象的数组,每个promise对象都代表一个异步操作。

2.调用promise.race:然后调用promise.race方法,并将这个数组作为参数传递给它。promise.race会返回一个新的promise对象

3.处理结果:

promise.race只关心第一个完成的promise对象(无论是成功还是拒绝)

如果第一个完成的promise是成功解析的,那么promise.race返回的promise对象也会解析,并且它的解析值与第一个完成的promise对象的解析值相同

如果过第一个完成的promise是被拒绝的,那么promise.race返回的promise对象也会被拒绝,并且它的拒绝原因第一个被决绝的promise对象的拒绝原因相同

4.使用.then和.catch:同样,也可以使用.then方法;来处理成功的情况,使用.catch方法来处理失败的情况。

例子:同时加载多张图片,但只显示第一张加载成功的图片

const urls = ['https://example.com/image1.jpg','https://example.com/image2.jpg','https://example.com/image3.jpg'
];const loadImage = (url) => {return new Promise((resolve, reject) => {const img = new Image();img.onload = () => {resolve(img);};img.onerror = () => {reject(new Error(`Failed to load image from ${url}`));};img.src = url;});
};Promise.race(urls.map(loadImage)).then((img) => {console.log('First image loaded successfully');document.body.appendChild(img);}).catch((error) => {console.error(error.message);});
// 创建两个异步操作的Promise,其中一个会更快完成
const slowFetch = () => new Promise((resolve) => {setTimeout(() => resolve('Slow Data'), 2000);
});const fastFetch = () => new Promise((resolve) => {setTimeout(() => resolve('Fast Data'), 500);
});// 使用 Promise.race 来等待第一个异步操作完成
Promise.race([slowFetch(), fastFetch()]).then((data) => {// 由于 fastFetch 更快完成,所以这里会输出 'Fast Data'console.log(data); // 输出: 'Fast Data'}).catch((error) => {// 如果没有任何Promise被拒绝,这里的catch不会被调用console.error(error);});// 另一个例子,包含一个会被拒绝的Promise
const fetchWithTimeout = () => {return Promise.race([fetch('https://jsonplaceholder.typicode.com/posts/1') // 一个真实的fetch请求.then(response => response.json()),new Promise((_, reject) => {setTimeout(() => reject(new Error('Request timed out')), 1000); // 1秒后拒绝})]);
};// 使用 fetchWithTimeout,并处理可能的超时
fetchWithTimeout().then(post => {console.log(post); // 如果fetch请求在1秒内完成,这里会输出post数据}).catch(error => {console.error('Error:', error.message); // 如果fetch请求超时,这里会输出 'Error: Request timed out'});

在这个fetchWithTimeout的例子中,我们使用了promise.race来设置一个超时机制。如果fetch请求在1秒内没有完成,那么promise.race会返回被拒绝的promise,并且我们可以在.catch中处理这个超时错误。

promise.resolve()和promise.reject()

promise.resolve()方法返回一个已经成功状态的promise对象,并将指定的值作为参数传递给它的then方法。

promise.reject()方法返回一个已经失败状态的promise对象,并将指定原因作为参数传递给它的catch方法
案例:

// Promise.resolve()
Promise.resolve(10).then((value) => {console.log(`The value is ${value}`); // 输出:The value is 10}).catch((error) => {console.error(error.message); // 不会执行});// Promise.reject()
Promise.reject('error').then((value) => {console.log(value); // 不会执行}).catch((reason) => {console.log(reason); // 输出:error});

二、高阶语法与特性

2.1模板字符串的高级用法

本小节讲解模板字符串的嵌套、标签模板等高级用法,了解它们如何用于字符串的格式化、插值等操作。

2.1.1.模板字符串的嵌套

模板字符串允许嵌套另一个模板字符串,这在处理复杂数据结构时非常有用。例如,假设有一个包含地址信息的数组,可以使用嵌套模板字符串来生成一个HTML表格:

const addrs = [{ first: 'John', last: 'Doe' },{ first: 'Jane', last: 'Smith' }
];const tmpl = addrs => `<table>${addrs.map(addr => `<tr><td>${addr.first}</td></tr><tr><td>${addr.last}</td></tr>`).join('')}</table>
`;console.log(tmpl(addrs));

上述代码中,内部的模板字符串用于生成每一行的表格内容,外部的模板字符串则负责将这些行组合成一个完整的表格。

2.1.2.标签模板用于字符串的格式化、插值等操作

标签模板(Tagged Template)是一种特殊的函数,它允许对模板字符串进行自定义处理。标签模板函数的基本语法是在一个函数名后面紧跟一个模板字符串字面量。这个函数会接收两个参数:一个由模板字符串中的静态文本部分组成的数组,以及由模板字符串中的表达式求值结果组成的剩余参数列表。

1.字符串格式化

可以创建一个标签模板函数来格式化日期、数字或货币等。例如,以下是一个简单的标签模板函数,用于将数字格式化为货币形式:

function formatCurrency(strings, ...values) {let result = '';for (let i = 0; i < strings.length; i++) {result += strings[i];if (i < values.length) {result += '$' + values[i].toFixed(2); // 将数字格式化为两位小数的货币形式}}return result;
}const price = 123.456;
console.log(formatCurrency`The price is ${price}`); // 输出 "The price is $123.46"
2.字符串插值:

标签模板函数也可以用于字符串插值,但与普通的模板字符串插值不同,标签模板函数可以对插入的变量或表达式进行自定义处理。例如,以下是一个将字符串转换为大写的标签模板函数:

function upperCase(strings, ...values) {return strings.reduce((result, str, i) => {const value = values[i - 1] || '';return result + str + value.toUpperCase();}, '');
}const greeting = upperCase`Hello, ${'world'}!`; // 输出 "Hello, WORLD!"
3. 避免XSS攻击

在处理用户输入时,标签模板函数还可以用于避免跨站脚本攻击(XSS)。例如,可以对用户输入进行HTML转义

function escapeHTML(strings, ...values) {let result = '';for (let i = 0; i < strings.length; i++) {result += strings[i];if (i < values.length) {// 简单的HTML转义函数const escape = (html) => html.replace(/[&<>"'`=\/]/g, (s) => `&#${s.charCodeAt(0)};`);result += escape(values[i]);}}return result;
}const userInput = '<script>alert("XSS!");</script>';
console.log(escapeHTML`Safe input: ${userInput}`); 
// 输出 "Safe input: &lt;script&gt;alert(&quot;XSS!&quot;);&lt;/script&gt;"

三、尾调用优化

3.1.尾调用优化(Tail Call Optimization)的概念和作用

尾调用优化是编译器或解释器对函数调用的一种优化手段。当函数A的最后一步是调用另一个函数B,并且A的返回值就是B的调用结果时,这个调用就被称为尾调用。如果编译器或解释器支持尾调用优化,那么在执行尾调用时,可以只保留函数B的调用记录,而删除函数A的调用记录,因为A的调用结果已经确定并且不再需要A的调用记录。这种优化可以显著减少内存使用,避免因为递归调用过深而导致的栈溢出错误。

3.2.递归函数中的尾调用优化

在递归函数中,尾调用优化尤为重要。传统的递归调用可能会导致大量的栈空间被占用,因为每次递归调用都会创建一个新的栈帧。而尾调用优化可以确保只有一个栈帧被重复使用,从而避免了栈空间的无谓消耗。

3.3.举例说明

已计算阶乘的递归函数为例,非尾递归和尾递归的实现方式如下:

非尾递归实现:

function factorial_recursive(n) {if (n === 0) {return 1;} else {return n * factorial_recursive(n - 1); // 这里不是尾调用,因为乘法操作在调用之后}
}

在这个非尾递归的实现中,每次递归调用之后都有一个乘法操作,因此这不是一个尾调用。编译器无法对这个递归调用进行优化。

尾递归实现:

function factorial_tail_recursive(n, result = 1) {if (n === 0) {return result;} else {return factorial_tail_recursive(n - 1, n * result); // 这里是尾调用,因为调用之后没有其他操作}
}

在这个尾递归的实现中,递归调用是函数的最后一个操作,并且这个调用的返回值就是整个函数的返回值。因此,编译器可以对这个递归调用进行优化,通过重用当前栈帧来避免增加额外的栈空间。

3.4.如何应用尾调用优化

要将一个递归函数改写为尾递归函数,通常需要引入一个辅助参数来保存中间结果。这个辅助参数在每次递归调用时都会被更新,并在递归结束时返回最终结果。

例2:计算斐波那契数列

非尾递归实现:

function fibonacci_non_tail_recursive(n) {if (n <= 1) {return n;} else {return fibonacci_non_tail_recursive(n - 1) + fibonacci_non_tail_recursive(n - 2);}
}

这个非尾递归的实现导致大量的重复计算和栈空间消耗。

尾递归实现

function fibonacci_tail_recursive(n, a = 0, b = 1) {if (n === 0) {return a;} else if (n === 1) {return b;} else {return fibonacci_tail_recursive(n - 1, b, a + b);}
}

在这个尾递归的实现中,我们引入了两个辅助参数 a 和 b 来保存斐波那契数列的前两个数。每次递归调用时,我们都会更新这两个参数,并在递归结束时返回最终结果。由于递归调用是函数的最后一个操作,并且这个调用的返回值就是整个函数的返回值,因此编译器可以对这个递归调用进行优化。

 四、模块化进阶

4.1.动态导入

4.1.1.基本语法

动态导入使用import()函数,该函数返回一个Promise对象。这意味着你可以使用.then()方法或async/await语法来处理导入的模块。以下是动态导入的常见写法:

1.导入整个模块:

import('./module.js').then((module) => {// 使用 module
});

2.导入模块的特定导出

import('./module.js').then(({ export1, export2 }) => {// 使用 export1 和 export2
});

4.1.2.动态导入的特点与优势

按需加载:动态导入允许你在需要时才加载模块,这有助于减少初始加载时间,提高应用性能。

代码分割:结合构建工具(如Webpack),动态导入可以实现代码分割,将代码拆分成更小的块,以便更高效地加载和执行。

条件加载:你可以根据条件动态加载不同的模块,这在实现功能切换或按需加载特定功能时非常有用。

4.1.3.动态导入的应用场景

按需加载组件:在单页面应用(SPA)中,你可以使用动态导入来按需加载组件,从而减少初始加载时间和内存占用。

条件加载模块:根据用户的操作或环境变量等条件,动态加载不同的模块以实现功能切换。

优化性能:通过代码分割和按需加载,动态导入可以显著提高应用的加载速度和性能。

4.1.4示例

使用动态导入根据条件加载不同模块

// 定义一个函数,根据不同的条件导入不同的模块
function loadModule(condition) {if (condition === 'moduleA') {return import('./moduleA.js');} else {return import('./moduleB.js');}
}// 使用 loadModule() 函数来动态导入模块
loadModule('moduleA').then((module) => {// 使用 moduleA 模块
}).catch((error) => {// 处理错误
});loadModule('moduleB').then((module) => {// 使用 moduleB 模块
}).catch((error) => {// 处理错误
});

在这个示例中,我们定义了一个loadModule函数,它根据传入的条件动态加载不同的模块。然后,我们使用loadModule函数来导入模块,并在Promisethen方法中使用相应的模块。

4.1.5.注意事项

兼容性:虽然大多数现代浏览器都支持动态导入,但在一些旧版浏览器中可能无法使用。因此,在开发过程中需要注意兼容性问题。

构建工具:为了充分利用动态导入的优势,通常需要结合构建工具(如Webpack)进行代码分割和优化。

错误处理:在使用动态导入时,需要妥善处理可能出现的错误,以确保应用的稳定性和用户体验。

4.2.循环依赖

循环依赖指的是两个或多个模块之间互相引用,形成一个闭环的依赖关系。这种依赖关系可能会导致一些潜在的问题,如模块加载顺序错误、未定义或未初始化的变量等。

4.2.1.循环依赖的定义与示例

循环依赖通常发生在以下情况:模块A依赖于模块B的导出,同时模块B也依赖于模块A的导出。这种依赖关系形成了一个闭环,可能导致模块加载和执行时的错误。

例如,有以下连个模块文件:

// a.js
import { b } from './b.js';export const a = () => {console.log('This is a.js');b();
};// b.js
import { a } from './a.js';export const b = () => {console.log('This is b.js');a();
};

在这个例子中,a.jsb.js互相引用对方,形成了一个循环依赖。

4.2.2.循环依赖的问题与影响

1.加载顺序问题:在循环依赖的情况下,模块的加载顺序变得不确定。这可能导致某些模块在还未完全初始化的情况下就被其他模块引用,从而引发错误。

2.未定义或未初始化的变量:由于加载顺序的不确定性,可能会出现某些变量在引用时还未被定义或初始化的情况。

3.性能问题:循环依赖可能导致模块加载和执行的效率降低,因为模块之间的依赖关系变得更加复杂。

4.2.3.解决循环依赖的方法

1.重构代码:通过重构代码来消除循环依赖。例如,可以将一些公共的功能或数据提取到一个新的模块中,并让其他模块都依赖于这个新模块。

2.使用异步加载:在ES6中,可以使用动态导入(import())来异步加载模块。这有助于在需要时才加载模块,从而避免循环依赖的问题。但需要注意的是,异步加载可能会增加代码的复杂性和加载时间。

3.依赖注入:通过依赖注入模式来管理模块之间的依赖关系。这有助于降低模块之间的耦合度,并使得依赖关系更加清晰和可控。

4.使用第三方库或工具:一些第三方库或工具(如Webpack的splitChunks插件)可以帮助开发者更好地管理和优化模块之间的依赖关系。

4.2.4.最佳实践与建议

1.避免循环依赖:在设计模块时,应尽量避免循环依赖的发生。通过合理的模块划分和组织,可以降低循环依赖的风险。

2.清晰的模块接口:确保每个模块都有清晰的接口和职责。这有助于其他模块更容易地理解和使用它们,并降低循环依赖的可能性。

3.使用构建工具:利用构建工具(如Webpack、Rollup等)来优化模块之间的依赖关系。这些工具可以帮助开发者更好地管理模块、减少打包文件的大小并提高加载速度。

亲爱的友友们~~~码这么多字不容易啊 给孩子点点赞叭,评论个1也成呐

当然上述内容若有遗漏或不足之处,恳请各位大佬不吝赐教,指正并帮助美化,以期更加完善。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/474167.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python+Django+MySQL+echarts+bootstrap制作的教学质量评价系统,包括学生、老师、管理员三种角色

项目介绍 该教学质量评价系统基于Python、Django、MySQL、ECharts和Bootstrap技术&#xff0c;旨在为学校或教育机构提供一个全面的教学质量评估平台。系统主要包括三种角色&#xff1a;学生、老师和管理员&#xff0c;每个角色有不同的功能权限。 学生角色&#xff1a;学生可…

找不到vcruntime140.dll怎么办,彻底解决vcruntime140.dll丢失的5种方法

当计算机系统中无法找到vcruntime140.dll这个特定的动态链接库文件时&#xff0c;可能会引发一系列运行问题&#xff0c;具体表现形式多样且影响范围较广。对于依赖于该文件运行的各类软件应用来说&#xff0c;缺失vcruntime140.dll将直接导致程序无法正常启动或执行&#xff0…

设计模式-Adapter(适配器模式)GO语言版本

前言 个人感觉Adapter模式核心就在于接口之间的转换。将已有的一些接口转换成其他接口形式。并且一般用于对象上&#xff0c;而不是系统上 问题 就用一个简单的问题&#xff0c;懂数据结构的同学可能知道双端队列。那么就用双端队列实现一个栈&#xff08;stack&#xff09;或…

表格的选择弹窗,选中后返显到表格中

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 表格的下拉框可以直接显示选项&#xff0c;那如果选择框不是下拉的&#xff0c;而是弹窗&#xff0c;那么在表格中如何返显呢&#xff1f; 问题描述 如上图所示&#xff0c;点击表格中的选择&#xf…

4.STM32之通信接口《精讲》之USART通信---实验串口发送程序

本节将进行实战&#xff0c;基础了解请查看第1&#xff0c;2&#xff0c;3节&#xff08;Whappy&#xff09; 开始背&#xff01;&#xff01; USART ---》全双工 异步/同步 点对点 C语言基础printf用法&#xff0c;这节将用到printf的重定向&#xff0c;来打印到串口助手上…

搭建MC服务器

局域网中玩MC&#xff0c;直接自己创建房间开启局域网就可以了。如果想开一个24小时不关机的服务器呢&#xff1f;其实最开始我是想在windows云服务器&#xff0c;图形化界面运行一个开启局域网即可。可能是云服务器上没有显卡&#xff0c;还是其他什么原因&#xff0c;游戏打开…

css 使用图片作为元素边框

先看原始图片 再看效果 边框的四个角灭有拉伸变形,但是图片的中部是拉伸的 代码 border-style: solid;/* 设置边框图像的来源 */border-image-source: url(/static/images/mmwz/index/bk_hd3x.png);/* 设置如何切割图像 */border-image-slice: 66;/* 设置边框的宽度 */border…

通用定时器---输出比较功能

目录 一、概念 二、输出比较的8种模式 三、输出比较输出PWM波形的基本结构 配置步骤 四、示例代码 一、概念 OC&#xff08;OutPut Compare&#xff09;输出比较。输出比较可以通过比较CNT与CCR寄存器的关系&#xff0c;来对输出电平进行置1/置0/翻转的操作&#xff0c;可…

【网页设计】CSS3 进阶(动画篇)

1. CSS3 2D 转换 转换&#xff08;transform&#xff09;是CSS3中具有颠覆性的特征之一&#xff0c;可以实现元素的位移、旋转、缩放等效果 转换&#xff08;transform&#xff09;你可以简单理解为变形 移动&#xff1a;translate旋转&#xff1a;rotate缩放&#xf…

探索 HTML 和 CSS 实现的 3D旋转相册

效果演示 这段HTML与CSS代码创建了一个包含10张卡片的3D旋转效果&#xff0c;每张卡片都有自己的边框颜色和图片。通过CSS的3D变换和动画&#xff0c;实现了一个动态的旋转展示效果 HTML <div class"wrapper"><div class"inner" style"-…

WTV芯片在智能电子锁语音留言上的应用方案解析

一、概述 电子锁的留言功能允许用户通过语音或文字方式给其他家庭成员留下信息。这项功能可以增强家庭成员之间的沟通&#xff0c;特别是在忙碌的家庭生活中提供便利。 WTV是一款功能强大的高品质语音芯片&#xff0c;采用了高性能32位处理器、最高频率可达120MHz。具有低成本、…

Ajax的相关内容

一、Ajax的使用步骤 1.创建XML对象 const xhrnew XMLHttpRequest(); 2.监听事件&#xff0c;处理响应 3.准备发送请求 true表示异步 ajax中永远是异步&#xff0c;永远是true 4.发送请求 二、GET和POST请求 三、JSON的三种形式 四、JSON的方法 五、跨域 六、XHR的属性和方法…

群控系统服务端开发模式-应用开发-前端级别功能开发

一、添加视图 在根目录下src文件夹下views文件夹下param文件夹下grade文件夹下&#xff0c;新建index.vue&#xff0c;代码如下 <template><div class"app-container"><div class"filter-container" style"float:left;"><…

【含开题报告+文档+PPT+源码】基于springboot的教师评价系统的设计与实现

开题报告 随着信息技术的迅猛发展&#xff0c;教育信息化已成为现代教育的必然趋势。教研室作为高校教学管理的重要机构&#xff0c;肩负着提升教学质量、推动教学改革的重要使命。然而&#xff0c;传统的教学管理方式往往存在效率低下、数据分散、管理不便等问题&#xff0c;…

Nginx 使用入门介绍

大家好&#xff0c;我是G探险者&#xff01; 今天聊一聊nginx. Nginx 是一款高性能的 Web 服务器、反向代理服务器以及负载均衡器。它因其轻量级、稳定性和高并发处理能力&#xff0c;在全球范围内得到了广泛应用。许多大型网站&#xff08;如 Netflix、Dropbox 和 WordPress…

Elasticsearch 重建索引 数据迁移

Elasticsearch 重建索引 数据迁移 处理流程创建临时索引数据迁移重建索引写在最后 大家都知道&#xff0c;es的索引创建完成之后就不可以再修改了&#xff0c;包括你想更改字段属性或者是分词方式等。那么随着业务数据量的发展&#xff0c;可能会出现需要修改索引&#xff0c;或…

vue3 路由写法及传参方式 !超详细

Vue Router 是 Vue.js 官方的路由管理器。它主要用于单页面应用程序&#xff08;SPA, Single Page Application&#xff09;中&#xff0c;帮助解决页面导航、组件复用等问题。 基本的使用 1.router配置文件代码 创建一个ts文件,用来写路由器 // 创建一个路由器,并暴露出去 …

有限状态机(续)

一、添加刀光和场景 1、资源链接&#xff1a; 武器刀光&#xff1a;https://assetstore.unity.com/packages/tools/particles-effects/melee-weapon-trail-1728 场景&#xff1a;https://assetstore.unity.com/packages/3d/environments/fantasy/casual-tiny-environment-ju…

内网安全隧道搭建-ngrok-frp-nps-sapp

1.ngrok 建立内网主机与公网跳板机的连接&#xff1a; 内网主机为客户机&#xff1a; 下载客户端执行 2.frp

模电数电,融会贯通

模电与数电在传统电子工程中似乎被划分为两大领域&#xff0c;然而&#xff0c;它们实际上是对同一器件的不同应用方法。这种观念有助于我们理解元器件在各种工作状态下的多样性&#xff0c;并在复杂的电路设计中实现更高效的系统集成。 一、三极管的多重身份&#xff1a;放大…