JavaScript对象与数组合并全解析:从浅拷贝到深合并的实战指南
1. 从一次线上事故说起为什么对象合并不是小事那天下午监控系统突然报警一个核心页面的用户数据展示大面积错乱。紧急排查后发现问题出在一个看似简单的操作上前端在处理从两个不同接口返回的用户配置信息时使用了错误的合并方式导致新配置覆盖了旧配置中的关键默认值最终引发了连锁反应。这次事故让我深刻意识到在JavaScript开发中对象和数组的合并操作远不是一句Object.assign()或[...arr1, ...arr2]那么简单。它直接关系到数据的完整性、状态的正确性甚至是应用的稳定性。无论是处理复杂的应用状态比如Redux中的state更新、合并API响应、配置项覆盖还是简单的数据处理我们几乎每天都在和对象与数组的合并打交道。然而不同的合并策略如浅合并、深合并、扩展合并在不同的场景下会带来截然不同的结果。用错了方法轻则导致UI显示异常重则引发难以追踪的业务逻辑错误。今天我们就来彻底拆解JavaScript中对象合并的4种核心方式和数组合并的4种常用方法不仅告诉你“怎么做”更要讲清楚“为什么这么做”以及“什么时候该用哪种”并结合我踩过的坑分享一些实战中的经验技巧。2. 对象合并的四种方式从浅尝辄止到深入骨髓对象合并的核心矛盾在于“覆盖”与“保留”的权衡。你是希望新属性完全覆盖旧属性还是希望进行某种程度的融合不同的方法给出了不同的答案。2.1 扩展运算符...最直观的浅合并扩展运算符是ES6带来的语法糖用于对象合并时非常简洁。const defaultConfig { port: 8080, host: localhost, logLevel: info }; const userConfig { host: 127.0.0.1, timeout: 5000 }; const finalConfig { ...defaultConfig, ...userConfig }; console.log(finalConfig); // 输出{ port: 8080, host: 127.0.0.1, logLevel: info, timeout: 5000 }工作原理与特性从右向左合并如果有同名属性右侧对象userConfig的属性值会覆盖左侧对象defaultConfig的。你可以合并多个对象优先级依次从右向左递增。浅合并Shallow Merge这是最关键的一点。它只合并对象自身可枚举的属性并且对于属性值是对象或数组的情况它复制的是引用而不是创建新的对象。const obj1 { a: 1, nested: { b: 2 } }; const obj2 { ...obj1 }; obj2.nested.b 999; console.log(obj1.nested.b); // 输出999原对象被修改了它不会合并对象的原型链上的属性。适用场景与避坑指南场景合并简单的配置对象、创建对象的浅拷贝、快速覆盖部分默认值。在React/Vue中合并Props或State当状态层级不深时非常常用。坑点最大的坑就是“浅合并”。当你合并的对象包含嵌套对象时修改合并后的对象可能会意外地修改源对象因为它们共享了同一个嵌套对象的引用。这在需要数据不可变Immutable的场景下是致命的。技巧如果你确定只需要浅合并并且源对象之后不会被修改那么扩展运算符是性能和可读性俱佳的选择。如果需要深合并必须配合其他手段。2.2Object.assign()经典的属性分配器Object.assign()是ES5引入的方法其行为与扩展运算符在对象合并上高度相似。const target { a: 1 }; const source1 { b: 2 }; const source2 { a: 3, c: 4 }; const result Object.assign(target, source1, source2); console.log(result); // 输出{ a: 3, b: 2, c: 4 } console.log(target); // 输出{ a: 3, b: 2, c: 4 } (target被修改了)工作原理与特性修改第一个参数目标对象这是它与扩展运算符最大的区别。Object.assign()会直接修改传入的第一个对象target并将其作为返回值。而扩展运算符会创建一个全新的对象。同样是浅合并和扩展运算符一样它只进行一层合并嵌套对象是引用复制。合并多个源对象它将第二个及之后的所有参数源对象的可枚举自有属性复制到目标对象。适用场景与避坑指南场景当你明确需要修改一个现有对象时。例如为一个已有的对象动态添加多个方法或属性。function MyClass() {} Object.assign(MyClass.prototype, { methodA() {}, methodB() {} });坑点副作用因为它会修改目标对象在函数式编程或强调不可变性的框架如Redux中这可能引发意料之外的副作用需要格外小心。不可枚举属性和Symbol属性默认情况下Object.assign不复制不可枚举属性和Symbol属性。但可以通过Object.getOwnPropertySymbols()等辅助实现。技巧为了避免副作用一个常见的模式是让第一个参数为一个空对象{}这样其行为就类似于扩展运算符且不会修改任何现有对象const result Object.assign({}, source1, source2);。2.3 手动递归合并实现深度控制的“深合并”当我们需要真正的深合并Deep Merge时前两种方法就力不从心了。这时我们需要手动实现或使用库提供的递归合并逻辑。核心思想是遍历对象的属性如果某个属性值在源对象和目标对象中都是普通对象则递归地合并它们否则直接用源对象的值覆盖。下面是一个简化版的深合并函数function deepMerge(target, source) { const output { ...target }; // 创建目标对象的浅拷贝作为起点 if (isObject(target) isObject(source)) { Object.keys(source).forEach(key { if (isObject(source[key])) { // 如果源对象的属性是对象 if (!(key in target)) { // 目标对象没有这个键直接赋值 output[key] source[key]; } else { // 目标对象也有这个键且值也是对象则递归合并 output[key] deepMerge(target[key], source[key]); } } else { // 如果源对象的属性不是对象是原始值或数组等直接覆盖 output[key] source[key]; } }); } return output; } function isObject(item) { return item typeof item object !Array.isArray(item); } // 使用示例 const objA { a: 1, nested: { b: 2, c: { d: 3 } } }; const objB { a: 99, nested: { b: 20, e: 5 }, newKey: hello }; const merged deepMerge(objA, objB); console.log(merged); // 输出{ a: 99, nested: { b: 20, c: { d: 3 }, e: 5 }, newKey: hello } objB.nested.e 100; // 修改源对象 console.log(merged.nested.e); // 输出5 (深合并后新对象与原对象无引用关系)工作原理与特性递归遍历函数会深入到对象的嵌套结构中进行合并。选择性覆盖对于非对象属性数字、字符串等直接覆盖对于对象属性则进入下一层递归。数组的处理上面的简单实现将数组视为普通值直接覆盖!Array.isArray(item)。在实际更完善的深合并中你可能需要定义数组的合并策略是覆盖、拼接concat还是去重合并这完全取决于业务需求。适用场景与避坑指南场景合并复杂的配置对象如webpack配置、深度合并状态树、处理来自不同层级的API数据。坑点循环引用如果对象内部存在循环引用如obj.a obj简单的递归函数会陷入死循环导致栈溢出。生产环境实现必须处理这种情况。特殊对象对Date、RegExp、Set、Map等内置对象直接...或Object.assign可能无法正确复制。深合并函数需要特殊处理这些类型。性能深度递归在大对象上可能有性能开销。技巧对于大多数项目不建议自己从头实现一个完美的深合并容易有遗漏和bug。推荐使用成熟的第三方库如 Lodash 的_.merge或_.mergeWith它们经过了充分测试处理了各种边界情况。_.mergeWith还允许你自定义合并逻辑非常灵活。2.4 使用Lodash的_.merge生产级的深合并方案在严肃的企业级项目中处理复杂的对象合并我强烈推荐使用Lodash的_.merge函数。它是一个健壮、功能完整的深合并工具。const _ require(lodash); // 或 import _ from lodash; const object { a: [{ b: 2 }, { d: 4 }] }; const other { a: [{ c: 3 }, { e: 5 }] }; const result _.merge(object, other); console.log(result); // 输出{ a: [{ b: 2, c: 3 }, { d: 4, e: 5 }] } // 注意它递归合并了数组内的对象元素而不是替换整个数组。工作原理与特性标准的深合并递归合并对象自身的和继承的可枚举属性。数组处理默认情况下_.merge会像合并对象一样通过索引递归合并数组元素。如果源值和目标值都是数组且对应索引位置都是对象则合并它们。这有时是想要的有时不是。自定义合并使用_.mergeWith可以自定义合并逻辑例如让数组直接拼接concat而不是按索引合并。function customizer(objValue, srcValue) { if (Array.isArray(objValue)) { return objValue.concat(srcValue); // 遇到数组就拼接 } } const result _.mergeWith({}, object, other, customizer);处理各种数据类型Lodash内部对普通对象、数组、以及类对象如Arguments对象都有相应的处理逻辑比手动实现更可靠。适用场景与避坑指南场景任何需要可靠、无副作用的深合并场景特别是处理来源未知、结构复杂的第三方数据或配置。坑点理解默认的数组合并行为_.merge按索引合并数组内对象的行为可能不符合你的直觉。如果你希望整个数组被替换或者以其他方式合并务必使用_.mergeWith或先进行浅拷贝再替换。包体积引入整个Lodash库可能较大。可以使用lodash/merge进行按需引入。技巧在Redux的Reducer中更新深层嵌套的state时_.merge是一个非常方便的工具可以让你写出更简洁、更声明式的更新逻辑避免繁琐的...展开操作。但要注意其不可变性——它返回的是新对象符合Redux的要求。3. 数组合并的四种方法连接、扩展与去重数组合并通常比对象合并更直观目标是将多个数组的元素整合到一个新数组中。根据是否需要去重、是否修改原数组也有不同选择。3.1Array.prototype.concat()老牌连接器concat()是数组原型上的方法用于合并两个或多个数组返回一个新数组不改变原数组。const arr1 [1, 2]; const arr2 [3, 4]; const arr3 [5, 6]; const mergedArr arr1.concat(arr2, arr3); console.log(mergedArr); // 输出[1, 2, 3, 4, 5, 6] console.log(arr1); // 输出[1, 2] (未改变)工作原理与特性不修改原数组这是一个纯函数返回全新的数组。浅拷贝元素如果数组成员是对象concat复制的是对象的引用新数组和原数组成员指向同一个对象。可以连接非数组值concat的参数如果不是数组会被直接作为元素添加到新数组末尾。arr1.concat(3, [4,5])得到[1,2,3,4,5]。适用场景与避坑指南场景需要向后兼容支持旧浏览器的简单数组合并。或者当你需要将一些值和一个数组合并时。坑点对于嵌套对象或数组依然是引用复制修改新数组中的对象会影响原数组。技巧在函数式编程中因为它不产生副作用所以很受欢迎。但在现代JS开发中其语法通常被更直观的扩展运算符取代。3.2 扩展运算符...现代语法下的优雅合并在数组合并上扩展运算符展现了其强大的表现力。const arr1 [a, b]; const arr2 [c, d]; const arr3 [e]; const mergedArr [...arr1, ...arr2, ...arr3]; console.log(mergedArr); // 输出[a, b, c, d, e]工作原理与特性展开数组元素它将数组“展开”为其各个元素。创建新数组与concat一样它返回一个新数组不修改原数组。同样也是浅拷贝。非常灵活你可以在合并时轻松插入其他元素。const newArr [start, ...arr1, middle, ...arr2, end];适用场景与避坑指南场景绝大多数需要合并数组的场景特别是ES6环境。代码简洁意图清晰。技巧这是目前最推荐的通用的数组合并方法可读性极高。在React中用于不可变地更新state数组非常常见setState({ items: [...state.items, newItem] })。3.3Array.prototype.push(...)原地追加的合并如果你不想创建新数组而是想将一个数组的所有元素追加到另一个数组的末尾并修改原数组可以使用push方法结合扩展运算符。const targetArr [1, 2]; const sourceArr [3, 4]; targetArr.push(...sourceArr); console.log(targetArr); // 输出[1, 2, 3, 4] (targetArr被修改) console.log(sourceArr); // 输出[3, 4] (sourceArr不变)工作原理与特性修改原数组目标数组push方法会改变调用它的数组。利用扩展运算符传参push方法本来接受一系列单独的参数。push(...sourceArr)相当于push(3, 4)从而将sourceArr的每个元素依次推入targetArr。高效当目标数组很大且你明确需要修改它时这比targetArr [...targetArr, ...sourceArr]创建全新数组可能更高效取决于引擎优化。适用场景与避坑指南场景需要高效地向一个现有数组批量添加元素并且可以接受副作用。例如在一个循环中不断累积结果。坑点明显的副作用在强调不可变性的代码中需避免使用。技巧这是push.apply(targetArr, sourceArr)的现代、更安全的替代写法。apply在数组非常大时可能有调用栈限制问题而扩展运算符没有这个问题。3.4 结合Set实现去重合并前面三种方法都是简单的连接不会去除重复元素。如果合并后需要去重最优雅的方式是借助ES6的Set数据结构。Set本身不允许重复值。const arr1 [1, 2, 3, 4]; const arr2 [3, 4, 5, 6]; // 方法一使用扩展运算符和Set const mergedUniqueArr1 [...new Set([...arr1, ...arr2])]; console.log(mergedUniqueArr1); // 输出[1, 2, 3, 4, 5, 6] // 方法二使用Array.from和Set const mergedUniqueArr2 Array.from(new Set(arr1.concat(arr2))); console.log(mergedUniqueArr2); // 输出[1, 2, 3, 4, 5, 6]工作原理与特性利用Set自动去重new Set(iterable)会创建一个Set并自动过滤掉传入的可迭代对象如数组中的重复值。再转回数组通过扩展运算符...或Array.from()将去重后的Set转换回数组。去重规则Set使用“SameValueZero”算法判断相等对于原始值数字、字符串很直观。但对于对象它比较的是引用所以两个内容相同但引用不同的对象不会被去重。适用场景与避坑指南场景合并多个来源的ID列表、标签列表等并确保结果唯一。坑点对象去重无效new Set([{a:1}, {a:1}])会得到两个元素因为它们是两个不同的对象引用。如果需要对象内容去重需要先序列化如转成JSON字符串或使用Map等更复杂的方法。NaN的处理Set认为NaN等于自身所以[NaN, NaN]去重后会只剩一个NaN这是符合预期的。技巧这是目前性能较好且代码简洁的去重方法。对于大型数组它通常比使用filter和indexOf的传统方法更快。4. 实战场景下的选择策略与性能考量了解了所有方法后关键在于如何根据实际场景做选择。这里没有一个放之四海而皆准的答案但有一些清晰的决策路径。4.1 对象合并选择策略选择对象合并方式的决策树可以简化为以下几个问题是否需要深合并否浅合并即可进入第2步。是直接选择手动递归深合并或使用Lodash的_.merge。对于生产环境强烈推荐后者除非你有极致的包大小控制需求且愿意承担自实现的风险。是否允许修改第一个源对象否需要不可变操作使用扩展运算符...。语法最简洁直观。是明确需要修改目标对象使用Object.assign(target, ...sources)。性能小贴士对于纯浅合并扩展运算符和Object.assign({}, ...)在大多数现代JS引擎中性能接近且都非常快。深合并由于涉及递归遍历性能开销与数据结构的深度和广度成正比。在性能关键路径如频繁执行的动画或滚动处理函数中应尽量避免深度合并大型对象可以考虑使用不可变数据库如Immer或更精细的状态管理。4.2 数组合并选择策略对于数组合并选择更直接是否需要去重是使用[...new Set([...arr1, ...arr2])]。否进入第2步。是否允许修改原数组否需要不可变操作使用扩展运算符...。这是现代JS的首选可读性最佳。是需要高效地向现有数组添加元素使用targetArr.push(...sourceArr)。是否需要考虑极老的浏览器如IE是回退到使用Array.prototype.concat()。否忽略此条。一个常见的综合案例Redux Reducer中的状态更新// 浅合并场景更新用户信息 function userReducer(state initialState, action) { switch (action.type) { case UPDATE_USER_INFO: // 使用扩展运算符返回全新的state对象符合Redux不可变要求 return { ...state, ...action.payload // 浅合并覆盖用户信息 }; default: return state; } } // 深合并场景更新嵌套的配置 function configReducer(state initialConfig, action) { switch (action.type) { case MERGE_DEEP_CONFIG: // 使用lodash的_.merge进行深合并 return _.merge({}, state, action.payload); default: return state; } } // 数组合并场景添加新项目到列表 function listReducer(state [], action) { switch (action.type) { case ADD_ITEM: // 使用扩展运算符不可变地添加新元素 return [...state, action.payload]; case ADD_MANY_ITEMS: // 合并多个新项目 return [...state, ...action.payload]; default: return state; } }4.3 关于“引用”的终极警告与最佳实践无论选择哪种合并方式只要涉及对象和数组就必须时刻警惕“引用”问题。浅拷贝包括扩展运算符、Object.assign、concat只复制一层嵌套的对象仍然是共享的。最佳实践默认使用不可变操作在React、Vue、Redux等生态中优先使用不修改原数据的方法扩展运算符、concat这能避免许多难以调试的副作用。深拷贝不是银弹不要一上来就无脑深拷贝。深拷贝如JSON.parse(JSON.stringify(obj))或_.cloneDeep性能消耗大且会丢失函数、Symbol、undefined等特殊值。只在确有必要时如需要完全隔离两段数据才使用。结构化共享对于超大型状态树可以考虑使用Immutable.js或Immer这类库。它们通过“结构共享”等技术在保证不可变性的同时提供高效的更新性能。Immer的“草稿”模式尤其符合直觉。代码清晰优于微优化在大多数业务场景下代码的可读性和可维护性比微小的性能差异更重要。{...obj}和[...arr]的意图一目了然应作为首选。对象与数组合并是JavaScript开发者工具箱中最基础也最常用的工具。理解它们之间的细微差别根据场景选择合适的方法能够让你写出更健壮、更易维护的代码。从那次线上事故后我们团队就对数据合并操作建立了Code Review检查点再小的合并也要求写明意图和确认深浅看似麻烦实则避免了很多潜在的风险。

相关新闻

独立开发者如何用AI智能体矩阵重构工作流:从Claude Code到Vercel的实战

独立开发者如何用AI智能体矩阵重构工作流:从Claude Code到Vercel的实战

1. 从“单兵作战”到“智能军团”的认知转变最近和几个独立开发者朋友聊天,发现一个挺有意思的现象:大家不再抱怨“一个人干三个人的活”有多累了,反而开始琢磨怎么用AI智能体矩阵,把“一个人”变成“一个团队”。这背后不是简单的…

2026/8/5 3:36:58 阅读更多 →
前端导航系统全解析:从页面跳转到响应式导航栏实战

前端导航系统全解析:从页面跳转到响应式导航栏实战

1. 从零开始:理解页面跳转与导航栏的本质如果你刚开始接触网页开发,可能会觉得“页面跳转”和“导航栏”是两个独立的概念。一个负责把用户带到不同的地方,另一个只是页面上的一排按钮。但在我十多年的前端开发经历里,我越来越觉得…

2026/8/5 3:36:55 阅读更多 →
从RAG到AI大脑:构建LLM智能体的长期记忆系统

从RAG到AI大脑:构建LLM智能体的长期记忆系统

1. 从RAG到AI大脑:为什么记忆是Agent的“灵魂”聊到大语言模型,大家现在最熟悉的可能就是RAG了。它就像一个临时抱佛脚的学生,每次回答问题前,赶紧去翻书(外部知识库),找到相关段落,…

2026/8/5 3:36:50 阅读更多 →

最新新闻

UML实战指南:十种图的核心价值、应用场景与避坑心法

UML实战指南:十种图的核心价值、应用场景与避坑心法

1. 项目概述:为什么我们需要重新审视UML的十种图?在软件开发的江湖里混了十几年,我见过太多项目从激情澎湃的启动会,最终走向混乱不堪的维护期。很多时候,问题的根源不在于代码写得不够“优雅”,而在于团队…

2026/8/6 7:57:41 阅读更多 →
Arm架构:从移动设备到数据中心,RISC设计如何重塑计算生态

Arm架构:从移动设备到数据中心,RISC设计如何重塑计算生态

1. 项目概述:为什么Arm架构无处不在?如果你最近几年买过手机、平板电脑,或者关注过苹果的Mac电脑,那么“Arm”这个词你一定不陌生。它不再是技术新闻里一个遥远的名词,而是已经实实在在地渗透到了我们每天使用的设备里…

2026/8/6 7:57:41 阅读更多 →
FDE 全景与价值

FDE 全景与价值

一、FDE 是什么1.1 定义FDE Forward Deployed Engineer,前线部署工程师。这里的 "前线" 指的是客户现场,而非战场。这个角色不是突然出现的,而是由一系列职责演进而来,并且仍在不断演化。1.2 起源:Palantir…

2026/8/6 7:57:41 阅读更多 →
UML类图实战指南:从核心概念到代码映射的软件设计沟通工具

UML类图实战指南:从核心概念到代码映射的软件设计沟通工具

1. 从“画图”到“设计”:为什么类图是程序员的核心沟通工具在软件开发的日常里,我们经常听到这样的话:“这个模块的接口怎么定义?”“这个对象和那个对象是什么关系?”“这个改动会不会影响其他功能?”如果…

2026/8/6 7:57:41 阅读更多 →
电子音乐制作技术解析:从IDM到Ambient Techno的音色与空间设计

电子音乐制作技术解析:从IDM到Ambient Techno的音色与空间设计

在电子音乐的发展长河中,2003年是一个承前启后的年份。这一年,由Kirk Degiorgio以As One为名发行的专辑《So Far (So Good)》,如同一颗被低估的遗珠,静静地躺在IDM、Downtempo、Ambient和Ambient Techno的交汇处。它没有喧嚣的宣发…

2026/8/6 7:57:41 阅读更多 →
Multisim仿真设计八路数显抢答器:数字电路核心模块与工程实践详解

Multisim仿真设计八路数显抢答器:数字电路核心模块与工程实践详解

1. 从零到一:为什么选择Multisim来设计抢答器?如果你是一名电子爱好者、电子工程专业的学生,或者正在准备电子设计竞赛,那么“用Multisim设计一个八路数显抢答器”这个项目,很可能就是你正在寻找的“练手神器”。乍一看…

2026/8/6 7:56:41 阅读更多 →

日新闻

深入解析LimboAI C++内核:架构设计与性能优化实战

深入解析LimboAI C++内核:架构设计与性能优化实战

1. 项目概述:为什么我们需要深入LimboAI的C内核?如果你是一名使用Godot引擎的游戏开发者,尤其是对AI行为逻辑有较高要求的项目,那么LimboAI这个名字你大概率不会陌生。它作为Godot 4生态中一个备受瞩目的行为树与状态机插件&#…

2026/8/6 0:00:06 阅读更多 →
Unity 2D游戏敌人AI系统:基于PlayMaker状态机与2D Toolkit的实战开发

Unity 2D游戏敌人AI系统:基于PlayMaker状态机与2D Toolkit的实战开发

1. 项目概述与核心思路大家好,我是老张,一个在游戏开发一线摸爬滚打了十多年的老码农。今天咱们接着聊《空洞骑士》风格2D动作游戏的Demo制作。上一期我们搭好了基础框架,处理了角色移动和碰撞,这一期,我们要让游戏世界…

2026/8/6 0:00:06 阅读更多 →
被动防火门市场前景发展趋势

被动防火门市场前景发展趋势

被动防火门依靠材质结构、密闭构造阻隔烟火蔓延,无需电控启动,是建筑被动消防系统核心构件,行业依托新规管控、城市更新、工业安全升级迎来稳定扩容,整体朝着合规化、专项化、低碳化、智能化方向发展。现阶段 GB12955‑2024 新版国…

2026/8/6 0:00:06 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/5 15:00:43 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/5 13:13:56 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/5 10:20:36 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/5 23:28:39 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/5 21:00:14 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/5 23:46:51 阅读更多 →