拓冰建站拓冰建站
首页 / 资讯中心 / 正文

蓝桥杯webJS

js类Array.filter()完整讲解基础定义filter是数组自带方法作用遍历数组筛选出满足条件的元素组成新数组返回不会修改原数组语法js运行const 新数组 原数组.filter( (item, index) { // 返回 true → 保留这个元素 // 返回 false → 剔除这个元素 })举最简单例子js运行const arr [10, 0, 20, 0, 30]; const res arr.filter(item item 0); console.log(res); // [10,20,30]大于 0 留下等于 0 扔掉。们一层一层由内向外拆开js运行obj[k].filter(ele ele.reduce((pre,now)prenow,0) 0)先明确变量含义obj[k]某一组的成员列表格式示例js运行[ [1,2,0,3,...9个数字], //成员1 ele [0,0,0,0,...], //成员2 ele [2,0,5,1,...] //成员3 ele ]第 1 层ele.reduce ((pre,now)prenow,0)ele是一个成员的 9 项指标数组例如[1,2,3,0,5,1,2,3,1]reduce作用数组累加求和语法说明js运行ele.reduce(回调函数, 初始值)pre累加器保存上一轮相加结果now当前遍历到的数组元素0初始值从 0 开始累加执行示例[1,2,3].reduce((pre,now)prenow,0)01 → 1 → 12 →3 →33 →6 得到总和 6。ele.reduce(...)该成员 9 个指标的总分第 2 层ele.reduce (...) 0判断这个人总分是否大于 0true成员有有效数据不全是 0false全部指标都是 0无效成员第 3 层外层 filterjs运行obj[k].filter( ele 【总分0】 )filter遍历组内每一个成员 ele 条件返回 true → 保留这个成员 条件返回 false → 剔除最终返回新数组当前小组所有拥有有效数据的成员集合完整语句通俗翻译取出第 k 小组里所有指标总和大于 0、存在有效填写数据的组员组成新数组。配套你代码里的用法js运行const validMembers obj[k].filter(eleele.reduce((pre,now)prenow,0)0) validMembers.lengthlength 0整组所有人全是 0 → zeroGrouplength 1只有 1 个人有数据 → unsupportable举一组实例直观感受js运行// obj[groupA] [ [0,0,0,0,0,0,0,0,0], //总和0 → 被过滤掉 [1,0,2,0,0,1,0,0,0], //总和4 → 保留 [0,3,0,0,2,0,1,0,0] //总和6 → 保留 ] validMembers 后两个成员length 2补充易错小点如果删掉 reduce 最后的初始值0js运行ele.reduce((pre,now)prenow) //不推荐当数组是空数组时会直接报错写上,0更安全规范写法方法作用返回值filter筛选留下符合条件元素新数组map遍历转换每个元素同等长度新数组forEach单纯循环无返回值undefinedMap对象.has () /.get () 完整讲解先记住Map是 JS 专门用来键值存储的数据结构比普通对象{}更适合分组场景。js运行const groupMap new Map()1.map.has(key)语法js运行map.has(键名)作用判断 Map 中是否存在这个 key返回布尔值true存在false不存在示例js运行const m new Map() m.set(g1, [成员数据]) console.log(m.has(g1)) // true console.log(m.has(g2)) // false你代码里写法js运行if (!map.has(ele.groupId))!是非取反 如果不存在这个小组 ID就新建一条记录。等价人话没有这个组我就创建。2.map.get(key)语法js运行map.get(键名)作用根据 key 取出对应的 value找不到 key 时返回undefinedjs运行const m new Map() m.set(g1, [[1,2,3]]) console.log(m.get(g1)) // [[1,2,3]] console.log(m.get(g99)) // undefined3.map.set(key, value)配套一起记往 Map 里添加 / 修改数据js运行map.set(ele.groupId, [memberData])结合你那段分组代码连起来看js运行if (!map.has(ele.groupId)) { map.set(ele.groupId, []); // 没有这个组 → 创建空数组 } map.get(ele.groupId).push(memberData); // 拿到数组push当前成员执行逻辑拆解判断有没有当前小组 ID没有 → 新建 key值是空数组用.get()获取该小组的成员数组把当前人的数据推进数组对比原来普通对象obj{}的写法原来js运行for(let k in obj){ if(ele.groupIdk){...} }需要循环遍历对比 key效率低。Map 优势.has()、.get()直接按键查找不用循环分组代码更简洁高效。易混小知识点对象{}的 key 只能是字符串 / SymbolMap的 key 可以是数字、对象等任意类型。map.has()不要写成map[key] ❌if(!map[ele.groupId])错误用法 ✅if(!map.has(ele.groupId))快速记忆口诀.has(key)有没有这个键 → 返回 true/false.get(key)拿这个键对应的值.set(key,val)设置键值// 对象转 mapobjToStrMap: function (obj) {// TODO待补充代码const result new Map()Object.keys(obj).forEach(e {result.set(e,obj[e]) })return result }这是Element UI / Element Plus 表单自定义校验规则 validatorjs运行validator: (rule, value, callback) { if (value ) { callback(请输入姓名) } else if (/[^\u4e00-\u9fa5]/g.test(value)) { callback(只能输入汉字) } else { callback() } }1. 参数说明rule当前这条校验规则配置对象一般不用value表单输入框当前的值callback校验回调函数必须调用callback(错误信息)→ 校验失败展示提示文字callback()不传参 → 校验通过2. 分支逻辑拆解①js运行if (value ) { callback(请输入姓名) }如果输入内容为空字符串 → 提示请输入姓名②js运行else if (/[^\u4e00-\u9fa5]/g.test(value)) { callback(只能输入汉字) }正则/[^\u4e00-\u9fa5]/g\u4e00-\u9fa5所有中文字符区间[^...]取反代表不是汉字.test(value)字符串里只要存在任意一个非汉字返回 true含义只要内容包含字母、数字、符号、空格等非汉字 → 报错【只能输入汉字】③js运行else { callback() }不为空 且 全部是汉字 → 校验成功⚠️ 当前代码存在的小问题不能匹配少数民族姓名带・例如买买提・阿里不允许输入空格全角空格也会判定非法如果你需要支持中文姓名中间的间隔号可以改成这个正则js运行/[^\u4e00-\u9fa5·]/g补充完整示例el-form-itemvueel-form-item label姓名 propname :rules[{ validator: 上面这段代码, trigger: blur }] el-input v-modelform.name/el-input /el-form-item拓展简化理解正则/[\u4e00-\u9fa5]/匹配汉字/[^\u4e00-\u9fa5]/匹配非汉字同步存储 vs 异步存储前端本地存储视角localStorage /sessionStorage/ 小程序存储先给核心结论同步存储代码等着读写完成阻塞主线程异步存储读写交给后台代码继续往下跑不阻塞。1. 通俗比喻同步存储localStorage、同步版小程序 storage你去柜台取钱必须站在原地等办完不能干别的。柜台操作期间所有人排队等待。 主线程卡住 → 页面卡顿、点击没反应。异步存储微信小程序 wx.setStorageAsync、IndexedDB、浏览器 Storage API 新版异步接口你提交取钱申请拿到一张回执单立刻可以去做别的事等后台处理完再通知你结果。 主线程不阻塞界面流畅。2. 关键区别对照表表格对比项同步存储异步存储线程行为阻塞主线程不阻塞主线程代码执行顺序等待执行完存储才走下一行立刻执行下一行存储在后台进行返回值直接返回数据返回 Promise需要 await /.then ()大数据场景文件 / 大量 JSON 极易造成页面卡顿适合存大量数据体验更好异常捕获直接 try-catch用 try-catch await 或者 .catch ()代表 APIlocalStorage.getItem()wx.getStorageSyncIndexedDBwx.setStorageAsync浏览器异步 KV 存储3. 代码直观对比微信小程序举例✅ 同步Sync—— 阻塞js运行// 主线程暂停直到读取结束 const data wx.getStorageSync(key) console.log(后面代码要等读取完才执行)✅ 异步Async—— 非阻塞js运行// 不等读取完成直接继续往下执行 wx.getStorageAsync(key).then(res { console.log(拿到数据) }) console.log(这行代码先执行)搭配 await 写法更常用js运行async function fn() { const res await wx.getStorageAsync(key) }4. 常见误区澄清不是异步就一定更快IO 耗时客观存在只是不会卡住页面同步只是把耗时直接摊在主线程上。localStorage 全部是同步浏览器原生 localStorage 没有异步版本大量循环读写 localStorage 会明显卡顿。 如果要存大量数据优先 IndexedDB异步。执行顺序陷阱异步不要直接在读取之后立刻使用变量数据还没回来js运行// 错误示范 let info wx.getStorageAsync(info).then(resinfores.data) console.log(info) // undefined还没读到5. 什么时候用哪个使用同步存储启动初始化少量配置、简单标记数据很小代码逻辑简单需要立刻拿到值使用异步存储优先推荐存储内容较大列表、大量对象用户交互场景滚动、点击时读写不想页面出现卡顿、掉帧6. 一句话终极总结同步存储操作完成前代码原地等待会卡界面异步存储发起操作后代码继续运行后台慢慢读写界面不卡顿但不能立刻拿到结果要用 Promise 接收代码解析js运行this.queue.length 0 wx.showLoading()1. 语法原理JS 短路与 A B如果A 结果为 true才会执行 B如果A 结果为 false直接跳过 BB 代码不会运行。等价于if 判断简写js运行if(this.queue.length 0){ wx.showLoading() }2. 整行含义mina-request 源码逻辑js运行this.queue.length 0 wx.showLoading()this.queue请求队列数组用来记录当前正在进行的请求数量this.queue.length 0当前没有正在跑的请求 含义当队列是空的时候才弹出 loading 加载框配套还有一行关键后面一定会有对应的关闭代码js运行this.queue.length 0 wx.hideLoading()逻辑所有请求全部完成、队列清空才关闭 loading这套设计目的解决多个请求并发场景页面同时发起 2 个接口第 1 个请求进来 → 队列由 0→1 → 弹出 loading第 2 个请求进来 → 队列 1→2 → 队列不为空不再重复弹出 loading第一个请求完成 → 队列 2→1 → 不关闭 loading第二个请求完成 → 队列 1→0 → 队列空关闭 loading✅ 效果多个请求并发时loading 只弹一次所有请求全部结束才消失 为什么控制台出现pewarn警告showLoading 与 hideLoading 必须配对使用产生警告的根源mina-request 内部维护请求队列正常流程请求发起 → 入队 → 队列空 → showLoading请求结束 → 出队 → 队列空 → hideLoading警告触发场景异常情况下队列数量错乱比如请求超时、请求取消、网络异常请求出队逻辑没执行queue 数组长度没有正常减 1队列永远不为 0hideLoading永远不会执行loading 卡死在页面上框架检测到队列失衡打印warn警告pewarn只是框架内部标记这条日志是警告级别 (print warn)不是语法是源码自定义标识。✅ 修复方案二选一方案 1使用最新标准拦截写法推荐你现在 http.jsjs运行// 请求拦截 instance.interceptors.request (config) { wx.showLoading({title:加载中}) return config } // 响应拦截成功、失败都会进入 instance.interceptors.response (res) { wx.hideLoading() return res }方案 2保留队列模式修复源码 bug如果你想用原生队列控制打开mina-request.js检查请求失败的回调里必须执行出队确保无论成功 / 失败都执行queue.pop()保证队列数量正常增减。通俗总结js运行this.queue.length 0 wx.showLoading()没有正在执行的请求时才显示加载弹窗有请求在跑不再重复弹出 loadingpewarn只是框架警告标记提醒你 loading 配对逻辑出现失衡风险。函数功能解读函数collectPuzzle(...puzzles) 接收多个数组参数剩余参数...puzzles将所有数组里的元素汇总去重返回一个包含全部不重复元素的一维数组。 示例调用collectPuzzle([1,2],[2,3],[3,4])→[1,2,3,4]方案 1截图中第一种写法逐行解析js运行function collectPuzzle(...puzzles) { let list [] puzzles.forEach(item{ // item 是传入的每一个子数组 new Set(item).forEach(it{ // Set(item) 先对子数组内部去重 // 如果list不存在该元素就push进去 !list.includes(it) list.push(it) }) }) return list }✅ 逻辑遍历所有传入的子数组先用Set清除单个子数组内部重复元素再判断全局数组 list 有无该元素实现全局去重⚠️ 缺点includes数组查找时间复杂度 O (n)数据量大时性能一般。方案 2截图注释的第二种写法js运行...puzzles剩余参数把传入的 3 个数组打包puzzles [[1,1,2], [2,3,3], [4]]注意只有写在函数参数最前面才叫剩余参数和别的地方的展开运算符长得一样但功能相反。...参数打包多个值 → 数组...数组拆包数组 → 零散的值核心判断法则先分清位置...在 JS 里有两种完全不同身份长得一模一样只能靠写在哪区分✅剩余参数Rest...变量名→打包零散值 → 数组 只出现在函数定义的形参js运行function fn(...puzzles){}✅展开运算符Spread...数组/集合→拆包数组 → 零散的值 出现在函数调用、数组字面量、push、对象字面量等地方js运行list.push(...new Set(item)) [...new Set(list)]一、快速判断流程图直接套用规则 1...写在【函数的形参位置】→ 剩余参数「打包」js运行// 函数定义 () 里面剩余参数打包 function collectPuzzle(...puzzles) {}含义把调用时传入多个独立参数收拢放进一个数组。js运行collectPuzzle([1,2],[3,4]) // puzzles [[1,2],[3,4]]限制只能放在形参最后一个function fn(a,...rest){}规则 2其他所有地方出现...→ 展开运算符「拆包」作用把数组 / Set 里面包裹的元素拆成一个个独立的值。js运行list.push(...new Set(item)) // 把Set{1,2} 拆开 → push(1,2) [...new Set(list)] // 把集合拆开放入新数组二、万能自测小技巧遇到任何... 直接用自问这个...是在 “装东西” 还是 “拆东西”打包剩余参数多个分散的值 → 装进数组 场景function abc(...arr){}拆包展开运算符数组 / 集合 → 打散成单个值 场景push、[]、函数传参直观对比示例① 打包剩余参数js运行function test(...nums){ console.log(nums) } test(1,2,3) // nums [1,2,3] ✅ 多个数字打包成数组② 拆包展开js运行const arr [1,2,3] console.log(...arr) // 等价 console.log(1,2,3) ✅ 数组拆开三、结合你代码里三处...逐个判断js运行// 1. 函数形参 → 剩余参数【打包】 function collectPuzzle(...puzzles) { let list [] puzzles.forEach(item{ // 2. push里面 → 展开运算符【拆包】 list.push(...new Set(item)) }) list Array.from(new Set(list)) // 等价写法[...new Set(list)] // 3. 数组字面量内 → 展开运算符【拆包】 return [...new Set(list)] }重点坑点不要混淆js运行// ❌误区以为...变量都是剩余参数 // 剩余参数只能出现在【函数定义】的括号内 // 其他地方一律是展开运算符 const arr [...puzzles] // 这里不是剩余参数只是展开拆包四、高频易错场景区分场景 1 push 中有没有... 巨大区别js运行const s new Set([1,2]) list.push(s) // 不拆list [Set{1,2}] list.push(...s) // 拆开list [1,2]场景 2 函数调用 vs 函数定义js运行// 定义...rest → 打包 function fn(...rest){} // 调用...arr → 拆包 fn(...[1,2,3]) //等价 fn(1,2,3)极简记忆口诀函数括号里定义参数...xxx 打包剩余参数其余任何位置...xxx 拆包展开运算符function collectPuzzle(...puzzles) { let list [] puzzles.forEach(item{ list.push(...new Set(item)) }) // 最后整体再一次去重 list Array.from(new Set(list)) return list }✅ 逻辑每个子数组先内部去重展开推入 list全部合并完成后一次性全局 Set 去重 ✅ 相比第一种写法更简洁性能更好推荐优先使用。最优简化版本推荐利用数组展开直接扁平化一行完成js运行function collectPuzzle(...puzzles) { // 先把所有子数组展开合并再Set全局去重 return [...new Set(puzzles.flat())] }解析puzzles.flat()扁平化二维数组把[[1,2],[2,3]]→[1,2,2,3]new Set()整体一次性去重[... ]Set 转回数组测试示例js运行console.log(collectPuzzle([1,1,2],[2,3,3],[4])) // 输出 [1,2,3,4]关键知识点小结...puzzles剩余参数调用时传入多个数组会打包成二维数组new Set(数组)快速去除数组内重复元素flat()二维数组扁平化ES2019Array.from(set)或[...set]集合转回普通数Math.ceil () 详解Math.ceil(数字)向上取整往更大的整数靠拢天花板函数。 ceil 英文含义天花板。appendParamsToURL 函数解析功能把对象里的键值对追加到 url 的查询参数search上返回拼接完成的 url 字符串。使用浏览器原生URLURLSearchParamsAPI不用手动拼接字符串、不用写?、、不用手动 url 编码这就是 “走捷径”。完整代码js运行/** * param {string} url 目标 URL * param {object} params 参数对象 * return {string} 拼接后的 url */ function appendParamsToURL(url, params) { const urlInstance new URL(url) for (const k in params) { urlInstance.searchParams.set(k, params[k]) } return urlInstance.toString() }逐行拆解const urlInstance new URL(url)原生 URL 构造器把 url 字符串解析成对象。 对象自带属性hostname、pathname、searchParams等等。for (const k in params)遍历传入的params对象所有 key。urlInstance.searchParams.set(k, params[k])searchParams是URLSearchParams实例专门管理 url 查询字符串。.set(key, value)设置查询参数。如果 url 原本就有这个 key会覆盖旧值没有就新增。✅自动做 URL 编码特殊字符、中文自动转义不用自己写encodeURIComponentreturn urlInstance.toString()把解析后的 URL 对象转回完整 url 字符串返回。测试示例js运行// 测试1原始url不带参数 console.log(appendParamsToURL(https://a.com/list, { id:1, name:张三 })) //输出https://a.com/list?id1name%E5%BC%A0%E4%B8%89 //测试2原始url已经有参数会覆盖 console.log(appendParamsToURL(https://a.com/list?id99, { id:100 })) //输出https://a.com/list?id100对比传统手动拼接不推荐js运行//老式写法麻烦容易出错还要处理? 编码 function badAppend(url, params){ let str for(let k in params){ str ${k}${encodeURIComponent(params[k])} } //还要判断url是否已经带?写三元非常繁琐 }题目里调侃 “谁还在拼接字符串和写一堆三元表达式捏”就是吐槽这种老式写法。URL内置 API 帮你全部处理边界。⚠️注意点set()会覆盖同名参数如果想要追加同一个 key允许重复 key要用.append()。如果 params 传入null/undefinedfor...in会报错生产环境最好增加判断js运行if(params typeof params object){ for (const k in params) { urlInstance.searchParams.set(k, params[k]) } }考试如果没有提这个边界直接写原题代码即可。set vs append表格方法行为set(k,v)该 key 只保留一个覆盖旧值append(k,v)保留旧值新增一条出现?k1k2拓展小练习调用js运行const res appendParamsToURL(https://demo.cn/goods?page1, {sort:price, page:2}) console.log(res) //结果https://demo.cn/goods?page2sortprice原来page1被 set 覆盖成page2新增 sort 参数。fadeIn (1000).fadeOut (1000) 详解jQuery 链式动画1. 基础含义fadeIn()淡入元素从透明慢慢显现出来fadeOut()淡出元素从可见慢慢消失变透明 数字单位毫秒 msjs运行$(img).fadeIn(1000).fadeOut(1000);执行顺序先用1000 毫秒1 秒把所有图片慢慢显示出来紧接着再用1000 毫秒1 秒把所有图片慢慢隐藏回去总耗时2000ms 2 秒 效果开局所有图片短暂亮一下又消失给玩家短暂记忆卡牌位置。2. jQuery 链式调用原理jQuery 支持连续打点调用动画动画会排队依次执行不会同时运行.fadeIn().fadeOut() 先做完淡入淡入彻底结束之后才开始执行淡出。3. 完整参数格式fadeIn(时长, 动画曲线, 回调函数)最后一个参数是动画结束回调动画全部跑完才会触发js运行$(img).fadeIn(1000).fadeOut(1000, function(){ // 淡入淡出整套动画全部结束后才执行这里 console.log(记忆预览结束可以开始翻牌了); isLock false; // 解除锁定允许玩家点击卡片 })为什么要加回调不加回调的问题 代码一运行就立刻绑定了点击事件玩家在图片闪烁的 2 秒内就能提前点击卡片逻辑错乱 写在回调里 必须等预览动画结束才开放点击体验更规范。4. 拆解视觉过程0~1s图片缓缓浮现1s~2s图片缓缓褪去2s 之后图片全部隐藏正式进入翻牌游戏5. 拓展写法简写数字fast200msslow600msjs运行$(img).fadeIn(slow).fadeOut(slow)想停顿一会再消失淡入完成后暂停片刻再淡出js运行$(img).fadeIn(1000).delay(1500).fadeOut(1000)delay (1500)淡入结束后停留 1.5 秒再开始淡出记忆时间更长。6. 和你游戏的搭配用途翻牌小游戏经典设计 开局快速展示一遍所有卡牌内容随即隐藏考验短时记忆之后玩家两两翻开配对。XSet 集合运算代码解析三个集合操作difference 差集、intersection 交集、union 并集XSet是封装的集合类类似 JS 原生Set。1. difference (a, b) 差集A‑B含义属于集合 a但不属于集合 b的元素。 ⚠️原代码直接执行a.delete(v)会直接修改传入的原集合 a副作用这是 bug不能直接改原始 a。static difference(a, b) { // 先复制一份a不要修改原集合 const res new XSet(a); for (const v of b) { res.delete(v); } return res; }错误点原题直接a.delete(v)会改动外部传入的 a 集合集合运算应当返回新集合不修改入参。2. intersection (a, ...bSets) 多集合交集含义所有集合共同拥有的元素。 参数a是第一个集合...bSets剩余多个集合。reduce迭代两两求交集不断缩小共同元素。 内部小函数f(a,b)求两个集合的交集返回数组。static intersection(a, ...bSets) { const f (a, b, r []) { for (const v of a) { for (const j of b) { if (v j) r.push(v); } } return r; } // reduce初始值acur上一轮交集结果prev下一个待求交集合 return new XSet(bSets.reduce((cur, prev)f(cur, prev), a)); }逻辑f(a,b)遍历 a、b找出同时存在于 a、b 的元素放到数组 r 返回。reduce拿第一个集合 a依次和后面每一个 bSet 做交集结果包装成XSet返回。示例intersection(set1,set2,set3) set1 ∩ set2 ∩ set33. union (a, ...bSets) 并集含义所有集合全部元素自动去重。 把 a 和所有 bSets 全部展开交给XSet自动去重。static union(a, ...bSets) { // reduce把全部bSets展开成一维数组 return new XSet([...a, ...bSets.reduce((cur, prev)cur.concat([...prev]), [])]); }JSreduce详解reduce是数组的归约方法把数组每一项循环累计、合并成一个最终值。arr.reduce(回调函数, [初始值])回调(cur, item, index, array) { ... }cur累计器上一轮返回的结果重点item当前遍历到的数组元素index当前下标很少用array原数组很少用通俗手里拿着cur上一轮结果拿item当前元素做计算return 出新值赋值给下一轮的cur。基础示例 1数组求和const arr [1,2,3,4]; // 初始值0 const sum arr.reduce((cur,item){ return cur item },0) // 过程 // 第1轮 cur0, item1 → return 1 // 第2轮 cur1, item2 → return 3 // 第3轮 cur3, item3 → return 6 // 第4轮 cur6, item4 → return 10 console.log(sum) //10基础示例 2拼接数组对应你作业里的 unionconst sets [ [1,2], [3,4], [5,6] ] const res sets.reduce((cur,prev){ return cur.concat(prev) },[]) //初始cur [] //第一轮 cur[], prev[1,2] → [][1,2] [1,2] //第二轮 cur[1,2], prev[3,4] → [1,2,3,4] //第三轮 cur[1,2,3,4], prev[5,6] → [1,2,3,4,5,6] console.log(res) //[1,2,3,4,5,6]看你作业里两处 reduce① intersection 交集bSets.reduce((cur,prev)f(cur, prev), a)bSets数组存放后面传入的多个集合初始值acur上一轮算出来的交集prev本次要参与求交的集合f(cur,prev)求 cur 与 prev 两个集合的交集返回结果给下一轮 cur逻辑(((a ∩ set1) ∩ set2) ∩ set3)② union 并集bSets.reduce((cur, prev)cur.concat([...prev]), [])初始值是空数组[]cur已经拼接好的数组prev当前集合[...prev]把集合转数组concat把集合里所有元素拼到 cur 数组⚠️reduce 两个大坑不写初始值数组为空时直接报错数组不为空会拿数组第 0 项作为第一轮 cur从第 1 项开始遍历很容易出 bug。建议永远写上初始值。arr.reduce((c,i)ci) //不写初始值不推荐 arr.reduce((c,i)ci, 0) //✅写上初始值回调里面必须 return不然下一轮 cur 变成undefinedreduce 能干什么求和、求积数组扁平化多维数组转一维你的 union 就是这个统计元素出现次数多轮迭代运算你的集合交集不断两两运算对象分组极简记忆reduce 不断循环拿着上一轮结果 (cur)和当前 item 运算return 给下一轮 cur第二个参数是 cur 的起点初始值。小练习看懂吗const arr [2,4,6] let r arr.reduce((c,i) ci, 10) //r等于多少答案10246 22拆解[...a]把集合 a 转为数组reduce遍历后面所有集合把每一个集合展开 concat 拼接到数组全部元素丢进new XSet()集合自动去除重复项。运算对照表表格方法数学含义说明difference(a,b)A‑B在 A不在 B返回新集合禁止修改原 aintersection(a,b,c…)A∩B∩C…全部集合共同元素union(a,b,c…)A∪B∪C…全部所有元素自动去重重点坑点考试常考difference 原始代码直接修改入参 a属于破坏性修改必须先拷贝副本// ❌错误原题写法直接修改传入的a for (const v of b) a.delete(v) return a外部使用这个函数之后外面原来的 a 集合元素被删掉引发 bug。...bSets是剩余参数接收除第一个 a 以外的全部传入集合。reduce 在这里做迭代归约两两运算。完整可运行修正版static difference(a, b) { const res new XSet(a); for (const v of b) { res.delete(v); } return res; } static intersection(a, ...bSets) { const f (a, b, r []) { for (const v of a) { for (const j of b) { if (v j) r.push(v); } } return r; } return new XSet(bSets.reduce((cur, prev)f(cur, prev), a)); } static union(a, ...bSets) { return new XSet([...a, ...bSets.reduce((cur, prev)cur.concat([...prev]), [])]); }
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门