
文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载导读filterRangeInPlace是《现代 JavaScript 教程》The Modern JavaScript Tutorial中「数组方法」章节1-js/05-data-types/05-array-methods的一道经典练习题它要求在不创建新数组的前提下从原数组中删除所有超出[a, b]区间的元素并强调函数不能有任何返回值。本文以该练习题为核心从题目约束出发逐层剖析基于splice的正向遍历解法、常见的索引错位陷阱并与姊妹题filterRange做对比最后结合仓库中自带的 Mocha 测试用例 给出可验证的完整实现。读完本文你将掌握数组「原位in-place修改」这一核心编程范式以及遍历过程中安全删除元素的标准写法。题目拆解三个必须满足的硬约束题目原文位于 task.md要求编写filterRangeInPlace(arr, a, b)它需要满足三个硬性约束区间判定保留满足a ≤ arr[i] ≤ b的元素删除区间之外的所有值区间边界a、b本身包含在内属于闭区间只改原数组函数应当直接修改传入的arr不创建并返回新数组无返回值函数「不应该返回任何东西」调用者无法通过返回值拿到结果。题目给出的示例let arr [5, 3, 8, 1]; filterRangeInPlace(arr, 1, 4); // 删除了范围在 1 到 4 之外的所有值 alert( arr ); // [3, 1]以a 1, b 4为例5和8超出区间被删除3和1落在闭区间[1, 4]内得以保留最终数组变为[3, 1]。第一步为什么不能直接使用 filter「过滤」最容易想到的工具是Array.prototype.filter。教程正文article.md 的 filter 小节明确指出filter会「返回所有匹配元素组成的数组」它不修改原数组。如果直接写function filterRangeInPlace(arr, a, b) { return arr.filter(item (a item item b)); }虽然逻辑正确但它在两个层面违背了题目的约束一是filter返回新数组而非修改arr原数组内容分毫未动二是函数有了返回值与「不应该返回任何东西」矛盾。这正是本题与姊妹题 filterRange2-filter-range 的本质区别——后者明确要求「不应该修改原数组返回新的数组」所以arr.filter(item (a item item b))一行即可完成见 其官方解答。可见筛选数据用filter就地删除则必须回到能够增删元素的splice。教程正文将splice称为「处理数组的瑞士军刀」它的完整语法为arr.splice(start[, deleteCount, elem1, ..., elemN])即从索引start开始删除deleteCount个元素并在当前位置插入可选的新元素。删除单元素的最简用法是arr.splice(i, 1)——从索引i处删掉 1 个元素后续元素自动前移填补空缺。第二步标准解法——正向遍历 splice 索引回退官方解答位于 solution.md核心代码如下function filterRangeInPlace(arr, a, b) { for (let i 0; i arr.length; i) { let val arr[i]; // 如果超出范围则删除 if (val a || val b) { arr.splice(i, 1); i--; } } }其配套的独立源码文件 _js.view/solution.js 与之完全一致。这个解法可以拆解为三个关键动作区间判定用val a || val b判断「超出区间」即删除条件取闭区间a ≤ val ≤ b的补集。注意边界值恰好等于a或b的元素不会被误删就地删除arr.splice(i, 1)删除当前元素数组长度减一后续元素整体前移填补了被删除元素留下的空位索引回退i--这是整个解法最精妙的一行。删除发生后原本位于i 1的元素移动到了i的位置。如果不回退紧接着的i会让循环跳过这个「顶替上来」的元素导致漏检i--配合循环自增等效于让指针重新指向同一个位置再检一次。逐步推演以题目示例为例对arr [5, 3, 8, 1]a 1b 4循环轮次检查元素是否删除删除后数组索引变化i 05超出是splice(0, 1)[3, 8, 1]i--回退到-1自增后回到0i 03在区间内否[3, 8, 1]i自增到1i 18超出是splice(1, 1)[3, 1]i--回退到0自增后回到1i 11在区间内否[3, 1]i自增到22 arr.length(2)不成立循环结束最终arr变为[3, 1]与题目预期完全一致。第三步经典陷阱——忘记索引回退会漏删如果去掉i--function filterRangeInPlace(arr, a, b) { for (let i 0; i arr.length; i) { if (arr[i] a || arr[i] b) { arr.splice(i, 1); // 忘记 i--删除后指针继续前移 } } }以arr [5, 3, 8, 1]推演i 0删除5后数组变为[3, 8, 1]i自增到1此时arr[1]是8——原本排在5后面的3被整体跳过且未被重新检查。这正是「删除元素导致后续元素前移、指针却继续前进」所引发的经典漏删问题。类似的正确解法还有两种常见变体均可避免索引回退从后往前遍历推荐用于原地删除场景function filterRangeInPlace(arr, a, b) { for (let i arr.length - 1; i 0; i--) { if (arr[i] a || arr[i] b) { arr.splice(i, 1); } } }删除i处的元素只影响i之后的索引而反向遍历时i之前的索引不受影响因此无需任何索引修正也不存在漏检问题。filter 结果驱动 splicefunction filterRangeInPlace(arr, a, b) { let removed 0; arr.forEach((val, i) { if (val a || val b) { arr.splice(i - removed, 1); removed; } }); }通过记录已删除个数removed补偿索引偏移。相比官方解法这两种写法在思路上各有侧重反向遍历更直观、无回退官方正向遍历则对「删除 索引修正」的底层机制展示得最为清晰。第四步用仓库自带的测试用例验证实现该练习目录下自带一套基于 Mocha 的测试 test.js从测试角度印证了题目的两个硬约束describe(filterRangeInPlace, function() { it(returns the filtered values, function() { let arr [5, 3, 8, 1]; filterRangeInPlace(arr, 2, 5); assert.deepEqual(arr, [5, 3]); }); it(doesnt return anything, function() { assert.isUndefined(filterRangeInPlace([1,2,3], 1, 4)); }); });两个用例分别验证功能正确性对[5, 3, 8, 1]调用filterRangeInPlace(arr, 2, 5)后用assert.deepEqual断言原数组被就地修改为[5, 3]8和1超出[2, 5]被删除无返回值用assert.isUndefined断言函数返回undefined——由于函数体没有return语句调用结果必然是undefined这正是「不应该返回任何东西」的代码级验证。姊妹题对照filterRange 与 filterRangeInPlace为了吃透「原位修改」这一概念强烈建议将本题与紧随其后的姊妹题 filterRange2-filter-range 对照学习二者处理同一份输入却走向完全不同的方向对比维度filterRange非原位filterRangeInPlace原位题目要求返回新数组不修改原数组只修改原数组不返回任何东西官方解法核心arr.filter(item (a item item b))for循环 arr.splice(i, 1)i--原数组状态保持[5, 3, 8, 1]不变被就地改为[3, 1]返回结果新数组[3, 1]undefined无返回值配套测试2-filter-range/_js.view/test.js3-filter-range-in-place/_js.view/test.js前者的解法solution.md用filter一行完成后者则必须借助splice就地修改。教程正文article.md 的总结小节也专门提醒「sort、reverse和splice方法修改的是数组本身」——splice属于典型的有副作用side-effect方法这正是本题选择它的根本原因。总结与延伸思考filterRangeInPlace虽然只是一道练习题却浓缩了数组编程中最重要的几个知识点区分「返回新数组」与「就地修改」filter、map、slice是纯函数式风格不碰原数组splice、sort、reverse则直接改写原数组。选择哪个取决于调用方是否需要保留原始数据遍历中删除元素的索引管理正向遍历配合splice时务必用i--补偿元素前移或者改用反向遍历从根上规避该问题无返回值设计函数只通过参数产生副作用时返回undefined是刻意为之的契约测试中用assert.isUndefined锁定了这一点。在此基础上可以继续深入探索教程「数组方法」整章还讲解了forEach、find、reduce、sort等其余方法若想进一步理解「原位 vs 复制」在不同场景下的取舍还可研读同一章中slice、concat与splice的对比示例以及本仓库其他练习如 2-filter-range、3-filter-range-in-place的完整解答。赞分享文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载相关推荐JavaScript 数组原位过滤实战用 splice 实现 filterRangeInPlaceJavaScript 数组原位过滤实战用 splice 实现 filterRangeInPlace 本文基于《现代 JavaScript 教程The Mod文档教程前端JavaScript 数组原地区间过滤实现 filterRangeInPlace 与 splice 的实战演练JavaScript 数组原地区间过滤实现 filterRangeInPlace 与 splice 的实战演练 导读 filterRangeInPlace a文档/教程前端Modern JavaScript Tutorial 精讲用 splice 实现数组区间过滤 filterRangeInPlace原地修改Modern JavaScript Tutorial 精讲用 splice 实现数组区间过滤 filterRangeInPlace原地修改 导读 本文围绕文档/教程前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考