如何用JavaScript实现卷积神经网络的前向传播?

JavaScript实现CNN前向传播需构建卷积、激活、池化、全连接等层,通过类型化数组、Web Workers、WebAssembly及GPU加速优化性能,并支持数据预处理、模型加载、交互式UI与跨平台部署,形成端到端AI应用生态。

如何用javascript实现卷积神经网络的前向传播?

在JavaScript中实现卷积神经网络的前向传播,核心在于理解并模拟数据流经卷积层、激活层、池化层和全连接层时的计算过程。这本质上是将数学运算——主要是矩阵乘法和元素级操作——用JavaScript的数组和循环结构重新构建出来,从而让模型能够接收输入数据并输出预测结果。

解决方案

要用JavaScript实现一个卷积神经网络(CNN)的前向传播,我们需要一步步构建构成CNN的各个核心层。这不像使用TensorFlow.js那样直接调用API,而是需要我们亲手“搭建”计算逻辑。

首先,输入数据通常是一个多维数组,比如图像,可以表示为

[height, width, channels]

1. 卷积层 (Convolutional Layer)这是CNN的灵魂。它的任务是通过一组可学习的滤波器(或称卷积核)从输入数据中提取特征。

滤波器 (Kernels): 每个滤波器也是一个小的多维数组,例如

[kernel_height, kernel_width, input_channels]

步长 (Stride): 滤波器在输入数据上滑动的步长。填充 (Padding): 为了处理边界像素,我们可能需要在输入数据周围添加零值。计算过程: 对于输出特征图的每个位置

(i, j)

和每个输出通道

k

,我们取输入数据中对应的一个“感受野”,与第

k

个滤波器的权重进行元素级乘法,然后求和。最后,加上一个偏置项

bias_k

JavaScript实现思路: 嵌套多层循环。外层循环遍历输出特征图的

height

width

,内层循环遍历滤波器的

height

width

和输入通道。

// 简化示例,未考虑padding和stride的复杂性function convolve(input, kernel, bias, stride = 1, padding = 0) {    const [inputH, inputW, inputC] = input.shape;    const [kernelH, kernelW, kernelC, outputC] = kernel.shape; // kernelC == inputC    const outputH = Math.floor((inputH - kernelH + 2 * padding) / stride) + 1;    const outputW = Math.floor((inputW - kernelW + 2 * padding) / stride) + 1;    // 初始化输出特征图    const output = Array(outputH).fill(0).map(() =>                    Array(outputW).fill(0).map(() =>                    Array(outputC).fill(0)));    // 实际的卷积操作    for (let oh = 0; oh < outputH; oh++) {        for (let ow = 0; ow < outputW; ow++) {            for (let oc = 0; oc < outputC; oc++) {                let sum = 0;                for (let kh = 0; kh < kernelH; kh++) {                    for (let kw = 0; kw < kernelW; kw++) {                        for (let ic = 0; ic = 0 && ih = 0 && iw < inputW) {                                sum += input.data[ih][iw][ic] * kernel.data[kh][kw][ic][oc];                            }                        }                    }                }                output[oh][ow][oc] = sum + bias.data[oc];            }        }    }    return { data: output, shape: [outputH, outputW, outputC] };}

这里为了简洁,

input.shape

input.data

只是一个示意,实际中可能需要更灵活的数据结构。

立即学习“Java免费学习笔记(深入)”;

2. 激活层 (Activation Layer)通常紧随卷积层之后,引入非线性。最常用的是ReLU (Rectified Linear Unit)。

ReLU:

f(x) = max(0, x)

JavaScript实现: 遍历上一步的输出特征图的每个元素,应用ReLU函数。

function relu(input) {    const output = input.data.map(h =>                    h.map(w =>                    w.map(c => Math.max(0, c))));    return { data: output, shape: input.shape };}

3. 池化层 (Pooling Layer)用于降采样,减少特征图的维度,同时保留重要信息,并增强模型的平移不变性。最常见的是Max Pooling。

Max Pooling: 在一个滑动窗口内取最大值。JavaScript实现: 遍历输入特征图,对于每个窗口,找到其中的最大值作为输出。

function maxPool(input, poolSize = 2, stride = 2) {    const [inputH, inputW, inputC] = input.shape;    const outputH = Math.floor((inputH - poolSize) / stride) + 1;    const outputW = Math.floor((inputW - poolSize) / stride) + 1;    const output = Array(outputH).fill(0).map(() =>                    Array(outputW).fill(0).map(() =>                    Array(inputC).fill(0)));    for (let oh = 0; oh < outputH; oh++) {        for (let ow = 0; ow < outputW; ow++) {            for (let c = 0; c < inputC; c++) {                let maxValue = -Infinity;                for (let ph = 0; ph < poolSize; ph++) {                    for (let pw = 0; pw < poolSize; pw++) {                        const ih = oh * stride + ph;                        const iw = ow * stride + pw;                        maxValue = Math.max(maxValue, input.data[ih][iw][c]);                    }                }                output[oh][ow][c] = maxValue;            }        }    }    return { data: output, shape: [outputH, outputW, inputC] };}

4. 展平层 (Flatten Layer)在将卷积和池化层的输出传递给全连接层之前,需要将多维特征图展平为一维向量。

JavaScript实现: 简单地将多维数组的所有元素按顺序提取到一个一维数组中。

function flatten(input) {    const flatData = [];    input.data.forEach(h => h.forEach(w => w.forEach(c => flatData.push(c))));    return { data: flatData, shape: [flatData.length] };}

5. 全连接层 (Fully Connected Layer)传统神经网络的层,每个输入神经元都连接到每个输出神经元。

计算过程: 输入向量与权重矩阵进行矩阵乘法,然后加上偏置向量。JavaScript实现: 遍历输出神经元,计算每个输出神经元的值(输入与对应权重的点积)。

function dense(input, weights, bias) {    const inputSize = input.shape[0];    const outputSize = weights.shape[1]; // weights.shape = [inputSize, outputSize]    const output = Array(outputSize).fill(0);    for (let j = 0; j < outputSize; j++) {        let sum = 0;        for (let i = 0; i < inputSize; i++) {            sum += input.data[i] * weights.data[i][j];        }        output[j] = sum + bias.data[j];    }    return { data: output, shape: [outputSize] };}

6. 输出层 (Output Layer)通常是另一个全连接层,如果进行分类任务,会加上Softmax激活函数。

Softmax: 将任意实数向量转换为概率分布,所有元素之和为1。JavaScript实现:

function softmax(input) {    const maxVal = Math.max(...input.data);    const expValues = input.data.map(val => Math.exp(val - maxVal)); // 减去maxVal防止溢出    const sumExp = expValues.reduce((a, b) => a + b, 0);    const output = expValues.map(val => val / sumExp);    return { data: output, shape: input.shape };}

将这些层串联起来,就构成了CNN的前向传播。例如:

input -> convolve -> relu -> maxPool -> flatten -> dense -> relu -> dense -> softmax -> output

在浏览器环境中运行JavaScript CNN模型时,性能优化有哪些关键考量?

说实话,用纯JavaScript手动实现CNN的前向传播,性能瓶颈是显而易见的。浏览器环境对CPU密集型计算并不友好,尤其是涉及到大量浮点运算和多层循环。在我看来,有几个关键点是不得不考虑的:

首先,数据结构的选择至关重要。原生的JavaScript数组在处理大量数值时效率不高,因为它们是动态类型且内存开销较大。使用

Float32Array

Float64Array

这样的类型化数组(Typed Arrays)可以显著提升性能,它们在内存中是连续存储的,更接近C/C++中的数组,CPU访问起来也更快。

其次,计算的卸载是必选项。直接在主线程中执行复杂的卷积和矩阵乘法,很可能会导致UI卡顿,用户体验会非常糟糕。

Web Workers是一个很好的选择,可以将这些繁重的计算放到后台线程中执行,避免阻塞主线程。结果计算完毕后,再通过

postMessage

传回主线程。WebAssembly (Wasm)是另一个更强大的工具。你可以用C++、Rust等语言编写高性能的CNN核心计算逻辑,然后编译成Wasm模块。Wasm在浏览器中以接近原生代码的速度运行,对于像矩阵乘法这样的CPU密集型任务,性能提升非常显著。很多现代的深度学习库,比如TensorFlow.js,内部都大量使用了Wasm来加速CPU端的计算。GPU加速 (WebGL/WebGPU)是终极解决方案。图形处理器(GPU)天生就擅长并行计算,尤其适合矩阵乘法这种高度并行的任务。TensorFlow.js等库就是通过WebGL(或未来的WebGPU)将计算任务发送到GPU上执行。虽然手动编写WebGL着色器来实现卷积层非常复杂,但如果追求极致性能,这是不可避免的方向。

此外,算法层面的优化也不可忽视。例如,矩阵乘法有多种优化算法(Strassen算法、Coppersmith-Winograd算法),虽然在JavaScript中直接实现这些可能过于复杂,但了解其原理有助于我们选择更高效的计算路径。避免不必要的内存分配和垃圾回收也是一个细节,在循环中频繁创建新数组会增加GC压力,尽量复用已有的内存空间。

最后,模型本身的复杂度也会直接影响性能。如果模型太大、层数太多、滤波器数量庞大,即便做了上述优化,浏览器端也可能难以流畅运行。这时候,模型量化、剪枝等技术就显得尤为重要,它们可以在一定程度上减小模型体积,降低计算量。

JavaScript实现卷积层和池化层,如何处理边界效应和不同步长?

处理边界效应和不同步长,是手动实现卷积和池化层时最让人头疼的细节之一,也是容易出错的地方。这直接关系到输出尺寸和计算的正确性。

1. 边界效应与填充 (Padding)

“Valid” Padding (无填充): 这是最简单的情况,不对输入进行任何填充。卷积核只在完全覆盖输入数据的区域进行滑动。

输出尺寸计算:

output_size = floor((input_size - kernel_size) / stride) + 1

优点: 不需要额外处理,计算直接。缺点: 随着层数增加,特征图尺寸会迅速缩小,边缘信息丢失较多。

“Same” Padding (同尺寸填充): 这种填充方式旨在让输出特征图的尺寸与输入特征图的尺寸(或在考虑步长后,尺寸保持一致比例)保持相同。这通常通过在输入数据的边缘添加零值来实现。

填充量计算: 为了实现”Same”填充,我们需要计算在输入数据周围添加多少层零。对于一个

kernel_size

stride

,所需的总填充量

P_total

通常是

kernel_size - 1

(如果

stride

为1)。这个总填充量会均匀分布在输入数据的两侧。

pad_top = floor(P_total / 2)
pad_bottom = P_total - pad_top

左右填充同理。输出尺寸计算:

output_size = floor(input_size / stride)

(当

stride=1

时,

output_size = input_size

)实现方式: 在卷积或池化操作之前,先创建一个新的、尺寸更大的输入数组,将原始数据复制到中心,并在边缘填充零。或者,在计算过程中,通过条件判断

if (ih >= 0 && ih = 0 && iw < inputW)

来模拟填充,即超出边界的区域视为零。后者的效率更高,因为它避免了创建和复制大型数组。

2. 不同步长 (Stride)

步长决定了卷积核或池化窗口在输入数据上每次移动的距离。

stride = 1

: 窗口每次移动一个像素/单位。输出尺寸最大,保留信息最多。

stride > 1

: 窗口每次移动多个像素/单位。这会有效地对特征图进行降采样,减少输出尺寸。对循环的影响: 在卷积或池化层的外层循环中,计算输出特征图的索引

oh

ow

时,需要将它们乘以

stride

来得到对应的输入特征图的起始索引。例如,在卷积层中,

ih = oh * stride + kh - padding;

iw = ow * stride + kw - padding;

这里的

oh * stride

ow * stride

就体现了步长的作用。

举个例子,假设一个

5x5

的输入,

3x3

的卷积核,

stride=2

padding=0

第一次滑动:覆盖

(0,0)

(2,2)

区域。第二次滑动(水平):由于

stride=2

,卷积核会从

(0,2)

开始,覆盖

(0,2)

(2,4)

区域。第三次滑动(垂直):卷积核从

(2,0)

开始,覆盖

(2,0)

(4,2)

区域。输出尺寸会是

2x2

手动处理这些细节时,我个人觉得最关键的是画图。在纸上画出输入、卷积核、步长和填充,一步步模拟计算,就能清晰地理解每个索引是如何映射的,避免那些令人抓狂的越界错误。

除了基础的前向传播,JavaScript在构建端到端深度学习应用时,还能承担哪些角色?

仅仅实现前向传播,虽然是核心,但对于一个完整的端到端深度学习应用来说,JavaScript能做的远不止这些。在我看来,它的角色越来越多样化,甚至可以说,JavaScript正在成为连接用户、数据和AI模型的“万能胶”。

数据预处理与加载: 这是任何AI应用的第一步。JavaScript在浏览器端可以:

图像/视频处理: 加载、解码、裁剪、缩放、灰度化、归一化等操作,例如使用

Canvas API

ImageBitmap

进行像素级操作。文本处理: 分词、编码、向量化等,尤其是在Node.js环境中,可以处理大量文本数据。音频处理: 使用

Web Audio API

进行音频录制、采样、特征提取。数据可视化: 在预处理过程中,用D3.js、Chart.js等库可视化数据分布、特征等,帮助理解数据。

模型加载与管理:

加载预训练模型: 无论是TensorFlow.js、ONNX.js还是其他框架,JavaScript都能方便地加载各种预训练模型(如Keras、PyTorch导出的模型)。这使得开发者可以利用社区的成果,而无需从头训练。模型版本控制与更新: 在Web应用中,可以实现模型的动态加载和更新,确保用户始终使用最新或最优的模型。

用户界面与交互: 这无疑是JavaScript的强项。

实时推理反馈: 比如在浏览器中实时识别人脸、手势,或者对用户输入的文本进行情感分析,并将结果即时展示在UI上。交互式AI体验: 构建用户可以调整模型参数、观察模型行为、甚至通过“涂鸦”来与模型互动的应用。数据标注工具: 开发基于Web的工具,帮助用户对数据进行标注,从而为模型训练提供高质量的数据集。

后端集成与API服务 (Node.js):

模型训练与部署: 虽然浏览器端不适合大规模训练,但Node.js可以在服务器端利用TensorFlow.js等库进行模型训练,或作为模型的API服务层,接收前端请求,进行推理并返回结果。数据管道: 构建端到端的数据处理和模型推理管道,从数据采集、清洗到模型预测,Node.js都能扮演重要角色。实时通信: 使用WebSocket与前端进行实时数据交换,例如在实时视频流中进行目标检测。

跨平台部署:

桌面应用: 使用Electron可以将Web技术打包成桌面应用,这意味着你的深度学习应用可以轻松部署到Windows、macOS、Linux。移动应用: React Native、Ionic等框架允许用JavaScript编写原生移动应用,将深度学习能力带到手机和平板上。

迁移学习与微调: 虽然完整训练大型模型很困难,但JavaScript环境可以用于对预训练模型的顶层进行微调(迁移学习),以适应特定的下游任务。这通常涉及较少的计算量,更适合在浏览器或Node.js环境中进行。

总的来说,JavaScript不再只是前端的脚本语言,它已经演变为一个全栈、跨平台的生态系统,在深度学习领域,它扮演着从用户交互到模型部署,再到数据处理和轻量级训练的多元角色,极大地降低了AI应用的开发门槛和部署复杂度。

以上就是如何用JavaScript实现卷积神经网络的前向传播?的详细内容,更多请关注创想鸟其它相关文章!

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

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月20日 14:20:40
下一篇 2025年12月20日 14:20:43

相关推荐

  • 如何在 VS Code 中解决折叠代码复制问题?

    解决 VS Code 折叠代码复制问题 在 VS Code 中使用折叠功能可以帮助组织长代码,但使用复制功能时,可能会遇到只复制可见部分的问题。以下是如何解决此问题: 当代码被折叠时,可以使用以下简单操作复制整个折叠代码: 按下 Ctrl + C (Windows/Linux) 或 Cmd + C …

    2025年12月24日
    000
  • 姜戈顺风

    本教程演示如何在新项目中从头开始配置 django 和 tailwindcss。 django 设置 创建一个名为 .venv 的新虚拟环境。 # windows$ python -m venv .venv$ .venvscriptsactivate.ps1(.venv) $# macos/linu…

    2025年12月24日
    000
  • 为什么前端固定定位会发生移动问题?

    前端固定定位为什么会出现移动现象? 在进行前端开发时,我们经常会使用CSS中的position属性来控制元素的定位。其中,固定定位(position: fixed)是一种常用的定位方式,它可以让元素相对于浏览器窗口进行定位,保持在页面的固定位置不动。 然而,有时候我们会遇到一个问题:在使用固定定位时…

    2025年12月24日
    000
  • 从初学到专业:掌握这五种前端CSS框架

    CSS是网站设计中重要的一部分,它控制着网站的外观和布局。前端开发人员为了让页面更加美观和易于使用,通常使用CSS框架。这篇文章将带领您了解这五种前端CSS框架,从入门到精通。 Bootstrap Bootstrap是最受欢迎的CSS框架之一。它由Twitter公司开发,具有可定制的响应式网格系统、…

    2025年12月24日
    200
  • 克服害怕做选择的恐惧症:这五个前端CSS框架将为你解决问题

    选择恐惧症?这五个前端CSS框架能帮你解决问题 近年来,前端开发者已经进入了一个黄金时代。随着互联网的快速发展,人们对于网页设计和用户体验的要求也越来越高。然而,要想快速高效地构建出漂亮的网页并不容易,特别是对于那些可能对CSS编码感到畏惧的人来说。所幸的是,前端开发者们早已为我们准备好了一些CSS…

    2025年12月24日
    200
  • 深入理解CSS框架与JS之间的关系

    深入理解CSS框架与JS之间的关系 在现代web开发中,CSS框架和JavaScript (JS) 是两个常用的工具。CSS框架通过提供一系列样式和布局选项,可以帮助我们快速构建美观的网页。而JS则提供了一套功能强大的脚本语言,可以为网页添加交互和动态效果。本文将深入探讨CSS框架和JS之间的关系,…

    2025年12月24日
    000
  • 项目实践:如何结合CSS和JavaScript打造优秀网页的经验总结

    项目实践:如何结合CSS和JavaScript打造优秀网页的经验总结 随着互联网的快速发展,网页设计已经成为了各行各业都离不开的一项技能。优秀的网页设计可以给用户留下深刻的印象,提升用户体验,增加用户的黏性和转化率。而要做出优秀的网页设计,除了对美学的理解和创意的运用外,还需要掌握一些基本的技能,如…

    2025年12月24日
    200
  • is与where选择器:提升前端编程效率的秘密武器

    is与where选择器:提升前端编程效率的秘密武器 在前端开发中,选择器是一种非常重要的工具。它们用于选择文档中的元素,从而对其进行操作和样式设置。随着前端技术的不断发展,选择器也在不断演化。而其中,is与where选择器成为了提升前端编程效率的秘密武器。 is选择器是CSS Selectors L…

    2025年12月24日
    000
  • 前端技巧分享:使用CSS3 fit-content让元素水平居中

    前端技巧分享:使用CSS3 fit-content让元素水平居中 在前端开发中,我们常常会遇到需要将某个元素水平居中的情况。使用CSS3的fit-content属性可以很方便地实现这个效果。本文将介绍fit-content属性的使用方法,并提供代码示例。 fit-content属性是一个相对于元素父…

    2025年12月24日
    000
  • 前端技术分享:利用fit-content实现页面元素的水平对齐效果

    前端技术分享:利用fit-content实现页面元素的水平对齐效果 在前端开发中,实现页面元素的水平对齐是一个常见的需求。尤其在响应式布局中,我们经常需要让元素根据设备的屏幕大小自动调整位置,使页面更加美观和易读。在本文中,我将分享一种利用CSS属性fit-content来实现页面元素的水平对齐效果…

    2025年12月24日
    000
  • 学完HTML和CSS之后我应该做什么?

    网页开发是一段漫长的旅程,但是掌握了HTML和CSS技能意味着你已经赢得了一半的战斗。这两种语言对于学习网页开发技能来说非常重要和基础。现在不可或缺的是下一个问题,学完HTML和CSS之后我该做什么呢? 对这些问题的答案可以分为2-3个部分,你可以继续练习你的HTML和CSS编码,然后了解在学习完H…

    2025年12月24日
    000
  • 聊聊怎么利用CSS实现波浪进度条效果

    本篇文章给大家分享css 高阶技巧,介绍一下如何使用css实现波浪进度条效果,希望对大家有所帮助! 本文是 CSS Houdini 之 CSS Painting API 系列第三篇。 现代 CSS 之高阶图片渐隐消失术现代 CSS 高阶技巧,像 Canvas 一样自由绘图构建样式! 在上两篇中,我们…

    2025年12月24日 好文分享
    200
  • 13 个实用CSS技巧,助你提升前端开发效率!

    本篇文章整理分享13 个前端可能用得上的 css技巧,包括修改输入占位符样式、多行文本溢出、隐藏滚动条、修改光标颜色等,希望对大家有所帮助! 修改输入占位符样式、多行文本溢出、隐藏滚动条、修改光标颜色、水平和垂直居中。多么熟悉的场景!前端开发者几乎每天都会和它们打交道,本文收集 13 个CSS技巧,…

    2025年12月24日
    000
  • 巧用距离、角度及光影制作炫酷的 3D 文字特效

    如何利用 css 实现3d立体的数字?下面本篇文章就带大家巧用视觉障眼法,构建不一样的 3d 文字特效,希望对大家有所帮助! 最近群里有这样一个有意思的问题,大家在讨论,使用 CSS 3D 能否实现如下所示的效果: 这里的核心难点在于,如何利用 CSS 实现一个立体的数字?CSS 能做到吗? 不是特…

    2025年12月24日 好文分享
    000
  • CSS高阶技巧:实现图片渐隐消的多种方法

    将专注于实现复杂布局,兼容设备差异,制作酷炫动画,制作复杂交互,提升可访问性及构建奇思妙想效果等方面的内容。 在兼顾基础概述的同时,注重对技巧的挖掘,结合实际进行运用,欢迎大家关注。 正文从这里开始。 在过往,我们想要实现一个图片的渐隐消失。最常见的莫过于整体透明度的变化,像是这样: 立即学习“前端…

    2025年12月24日 好文分享
    000
  • 聊聊CSS中怎么让auto height支持过渡动画

    css如何让auto height完美支持过渡动画?下面本篇文章带大家聊聊css中让auto height支持过渡动画的方法,希望对大家有所帮助! 众所周知,高度在设置成auto关键词时是不会触发transition过渡动画的,下面是伪代码 div{ height: 0; transition: 1…

    2025年12月24日 好文分享
    000
  • 看看这些前端面试题,带你搞定高频知识点(一)

    每天10道题,100天后,搞定所有前端面试的高频知识点,加油!!!,在看文章的同时,希望不要直接看答案,先思考一下自己会不会,如果会,自己的答案是什么?想过之后再与答案比对,是不是会更好一点,当然如果你有比我更好的答案,欢迎评论区留言,一起探讨技术之美。 面试官:给定一个元素,如何实现水平垂直居中?…

    2025年12月24日 好文分享
    300
  • 看看这些前端面试题,带你搞定高频知识点(二)

    每天10道题,100天后,搞定所有前端面试的高频知识点,加油!!!,在看文章的同时,希望不要直接看答案,先思考一下自己会不会,如果会,自己的答案是什么?想过之后再与答案比对,是不是会更好一点,当然如果你有比我更好的答案,欢迎评论区留言,一起探讨技术之美。 面试官:页面导入样式时,使用 link 和 …

    2025年12月24日 好文分享
    200
  • 看看这些前端面试题,带你搞定高频知识点(三)

    每天10道题,100天后,搞定所有前端面试的高频知识点,加油!!!,在看文章的同时,希望不要直接看答案,先思考一下自己会不会,如果会,自己的答案是什么?想过之后再与答案比对,是不是会更好一点,当然如果你有比我更好的答案,欢迎评论区留言,一起探讨技术之美。 面试官:清除浮动有哪些方式? 我:呃~,浮动…

    2025年12月24日 好文分享
    000
  • 看看这些前端面试题,带你搞定高频知识点(四)

    每天10道题,100天后,搞定所有前端面试的高频知识点,加油!!!,在看文章的同时,希望不要直接看答案,先思考一下自己会不会,如果会,自己的答案是什么?想过之后再与答案比对,是不是会更好一点,当然如果你有比我更好的答案,欢迎评论区留言,一起探讨技术之美。 面试官:请你谈一下自适应(适配)的方案 我:…

    2025年12月24日 好文分享
    000

发表回复

登录后才能评论
关注微信