如何实现JavaScript的Map和Filter函数?

简介: 译者按: 鲁迅曾经说过,学习JavaScript最好方式莫过于敲代码了!原文: Master Map & Filter, Javascript’s Most Powerful Array Functions译者: Fundebug为了保证可读性,本文采用意译而非直译。

译者按: 鲁迅曾经说过,学习JavaScript最好方式莫过于敲代码了!

原文: Master Map & Filter, Javascript’s Most Powerful Array Functions

译者: Fundebug

为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。

这篇文章面向那些已经熟练使用for循环,但对Array.map和Array.filter并没有特别理解的开发者。本文将会手把手去实现这两个函数,来深入理解它们的工作原理。

Array.map

Array.map通过对输入的数组中每一个元素进行变换,返回由变换后的元素按序组成的新数组。原始数组的值不会被修改。假设我们相对一个数组中的每一个元素乘以3,使用for循环可以这样写。

for循环

var originalArr = [1, 2, 3, 4, 5];
var newArr = [];
for(var i = 0; i < originalArr.length; i++) {
    newArr[i] = originalArr[i] * 3;
}
console.log(newArr); // -> [3, 6, 9, 12, 15]
AI 代码解读

接下来我们将这个for循环抽象成一个函数。

multiplyByThree函数

var originalArr = [1, 2, 3, 4, 5];
function multiplyByThree(arr) {
    var newArr = [];
    
    for(var i = 0; i < arr.length; i++) {
        newArr[i] = arr[i] * 3;
    }
    return newArr;
}
var arrTransformed = multiplyByThree(originalArr);
console.log(arrTransformed); // -> [3, 6, 9, 12, 15]
AI 代码解读

现在我们继续深化这个抽象思路,将multiplyByThree中对每一个元素乘以3部分抽象为一个新的函数。

var originalArr = [1, 2, 3, 4, 5];
function timesThree(item) {
    return item * 3;
}
function multiplyByThree(arr) {
    var newArr = [];
    
    for(var i = 0; i < arr.length; i++) {
        newArr[i] = timesThree(arr[i]);
    }
    return newArr;
}
var arrTransformed = multiplyByThree(originalArr);
console.log(arrTransformed); // -> [3, 6, 9, 12, 15]
AI 代码解读

这样有什么好处呢?设想如果我们想对每一个元素乘以5,或则10,我们还要把整个for循环写一遍吗!
如果我们对timesThree函数稍作修改,就可以轻松的复用很多代码。

multiply函数

我们将:

function multiplyByThree(arr) {
    var newArr = [];
    
    for(var i = 0; i < arr.length; i++) {
        newArr[i] = timesThree(arr[i]);
    }
    return newArr;
}
AI 代码解读

重构为:

function multiply(arr, multiplyFunction) {
    var newArr = [];
    
    for(var i = 0; i < arr.length; i++) {
        newArr[i] = multiplyFunction(arr[i]);
    }
    return newArr;
}
AI 代码解读

我们将multiplyByThree重命名为multiply,并增加了一个参数。该参数是一个函数,定义了数组元素的变换规则。通过定义一个timesThree函数来达到实现对每一个数组元素乘以3的目的。

var originalArr = [1, 2, 3, 4, 5];
function timesThree(item) {
    return item * 3;
}
var arrTimesThree = multiply(originalArr, timesThree);
console.log(arrTimesThree); // -> [3, 6, 9, 12, 15]
AI 代码解读

有何优点呢?我们可以很简单定义任何变换:

var originalArr = [1, 2, 3, 4, 5];
function timesFive(item) {
    return item * 5;
}
var arrTimesFive = multiply(originalArr, timesFive);
console.log(arrTimesFive); // -> [5, 10, 15, 20, 25]
AI 代码解读

Map

我们进一步抽象:

function multiply(arr, multiplyFunction) {
    var newArr = [];
    
    for(var i = 0; i < arr.length; i++) {
        newArr[i] = multiplyFunction(arr[i]);
    }
    return newArr;
}
AI 代码解读

将multiply改为map, multiplyFunction改为transform:

function map(arr, transform) {
    var newArr = [];
    
    for(var i = 0; i < arr.length; i++) {
        newArr[i] = transform(arr[i]);
    }
    return newArr;
}
AI 代码解读

我们可以将任何对单个元素操作的函数传入map函数。比如,我们将所有字符都变换成大写:

function makeUpperCase(str) {
   return str.toUpperCase();
}
var arr = ['abc', 'def', 'ghi'];
var ARR = map(arr, makeUpperCase);
console.log(ARR); // -> ['ABC', 'DEF, 'GHI']
AI 代码解读

Array.map

我们定义的map函数和原生的Array.map还是有区别的:数组不再需要作为第一个参数传入,而是在点(.)的左侧。如果使用我们定义的map函数,如下:

function func(item) {
   return item * 3;
}
var arr = [1, 2, 3];
var newArr = map(arr, func);
console.log(newArr); // -> [3, 6, 9]
AI 代码解读

将其改写为使用Array.map函数的形式:

function func(item) {
   return item * 3;
}
var arr = [1, 2, 3];
var newArr = arr.map(func);
console.log(newArr); // -> [3, 6, 9]
AI 代码解读

Arrary.map参数解析

除了变换函数外,Array.map还可以接收其它两个参数: 数组索引(index), 原始的数组。

function logItem(item) {
    console.log(item);
}
function logAll(item, index, arr) {
    console.log(item, index, arr);
}
var arr = ['abc', 'def', 'ghi'];
arr.map(logItem); // -> 'abc', 'def', 'ghi'
arr.map(logAll); // -> 'abc', 0, ['abc', 'def', 'ghi']
                 // -> 'def', 1, ['abc', 'def', 'ghi']
                 // -> 'ghi', 2, ['abc', 'def', 'ghi']
AI 代码解读

因此,你可以再变换函数中使用索引和原始的数组。比如:你想要将一个列表变为带序号的列表,则需要使用索引(index)参数:

function multiplyByIndex(item, index) {
    return (index + 1) + '. ' + item;
}
var arr = ['bananas', 'tomatoes', 'pasta', 'protein shakes'];
var mappedArr = arr.map(multiplyByIndex);
console.log(mappedArr); // ->
// ["1. bananas", "2. tomatoes", "3. pasta", "4. protein shakes"]
AI 代码解读

因此,我们自己实现的map函数也应该支持这两个参数:

function map(arr, transform) {
    var newArr = [];
    
    for(var i = 0; i < arr.length; i++) {
        newArr[i] = transform(arr[i], i, arr);
    }
    return newArr;
}
AI 代码解读

当然,Array.map函数还有一些错误检查和执行优化的代码,我们定义的map只编码了核心功能。

Array.filter

Array.filter将数组中不满足条件的元素过滤,我们可以用for循环加上Array.push来实现。

for-loop

下面这段JS代码将所有大于5的元素筛选出来:

var arr = [2, 4, 6, 8, 10];
var filteredArr = [];
for(var i = 0; i < arr.length; i++) {
    if(arr[i] > 5) {
        filteredArr.push(arr[i]);
    }
}
console.log(filteredArr); // -> [6, 8, 10]
AI 代码解读

我们可以抽象这段代码,定义为一个函数:

function filterLessThanFive(arr) {
    var filteredArr = [];
    for(var i = 0; i < arr.length; i++) {
        if(arr[i] > 5){
            filteredArr.push(arr[i]);
        }
    }
    return filteredArr;
}
var arr1 = [2, 4, 6, 8, 10];
var arr1Filtered = filterLessThanFive(arr1);
console.log(arr1Filtered); // -> [6, 8, 10]
AI 代码解读

进一步抽象,将过滤条件抽出来:

function isGreaterThan5(item) {
    return item > 5;
}
function filterLessThanFive(arr) {
    var filteredArr = [];
    for(var i = 0; i < arr.length; i++) {
        if(isGreaterThan5(arr[i])) {
            filteredArr.push(arr[i]);
        }
    }
    return filteredArr;
}
var originalArr = [2, 4, 6, 8, 10];
var newArr = filterLessThanFive(originalArr);
console.log(newArr); // -> [6, 8, 10]
AI 代码解读

将过滤条件函数作为参数传入:

function filterBelow(arr, greaterThan) {
    var filteredArr = [];
    for(var i = 0; i < arr.length; i++) {
        if(greaterThan(arr[i])) {
            filteredArr.push(arr[i]);
        }
    }
    return filteredArr;
}
var originalArr = [2, 4, 6, 8, 10];
AI 代码解读

大功告成!我们可以使用如下代码来取出所有大于5的元素:

function isGreaterThan5(item) {
    return item > 5;
}
var newArr = filterBelow(originalArr, isGreaterThan5);
console.log(newArr); // -> [6, 8, 10];
AI 代码解读

Array.filter

我们将filterBelow重命名为filter, greaterThan重命名为testFunction:

function filter(arr, testFunction) {
    var filteredArr = [];
    for(var i = 0; i < arr.length; i++) {
        if(testFunction(arr[i])) {
            filteredArr.push(arr[i]);
        }
    }
    return filteredArr;
}
AI 代码解读

这就是一个基本的Array.filter函数了!

var arr = ['abc', 'def', 'ghijkl', 'mnopuv'];
function longerThanThree(str) {
    return str.length > 3;
}
var newArr1 = filter(arr, longerThanThree);
var newArr2 = arr.filter(longerThanThree);
console.log(newArr1); // -> ['ghijkl', 'mnopuv']
console.log(newArr2); // -> ['ghijkl', 'mnopuv']
AI 代码解读

同样,Array.filter也有索引(index)和原始数组这两个额外参数。

function func(item, index, arr) {
    console.log(item, index, arr);
}
var arr = ['abc', 'def', 'ghi'];
arr.filter(func); // -> 'abc', 0, ['abc', 'def', 'ghi']
                  // -> 'def', 1, ['abc', 'def', 'ghi']
                  // -> 'ghi', 2, ['abc', 'def', 'ghi']
AI 代码解读
img_ea207c7ffd843f2e46ed4001365c97a8.jpe

版权声明:
转载时请注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2017/07/26/master_map_filter_by_hand_written/

目录
打赏
0
0
0
0
235
分享
相关文章
JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、复杂API请求、DOM操作、搜索和过滤等,array.map()的使用详解(附实际应用代码)
array.map()可以用来数据转换、创建派生数组、应用函数、链式调用、异步数据流处理、复杂API请求梳理、提供DOM操作、用来搜索和过滤等,比for好用太多了,主要是写法简单,并且非常直观,并且能提升代码的可读性,也就提升了Long Term代码的可维护性。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
JavaWeb JavaScript ③ JS的流程控制和函数
通过本文的详细介绍,您可以深入理解JavaScript的流程控制和函数的使用,进而编写出高效、可维护的代码。
77 32
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
柯里化是一种强大的函数式编程技术,它通过将函数分解为单参数形式,实现了灵活性与可复用性的统一。无论是参数复用、延迟执行,还是函数组合,柯里化都为现代编程提供了极大的便利。 从 Redux 的选择器优化到复杂的数据流处理,再到深度嵌套的函数优化,柯里化在实际开发中展现出了非凡的价值。如果你希望编写更简洁、更优雅的代码,柯里化无疑是一个值得深入学习和实践的工具。从简单的实现到复杂的应用,希望这篇博客能为你揭开柯里化的奥秘,助力你的开发之旅! 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
本文介绍了JavaScript中常用的函数和方法,包括通用函数、Global对象函数以及数组相关函数。详细列出了每个函数的参数、返回值及使用说明,并提供了示例代码。文章强调了函数的学习应结合源码和实践,适合JavaScript初学者和进阶开发者参考。
65 2
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
除了 Generator 函数,还有哪些 JavaScript 异步编程解决方案?
【10月更文挑战第30天】开发者可以根据具体的项目情况选择合适的方式来处理异步操作,以实现高效、可读和易于维护的代码。
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
JS函数提升 变量提升
【10月更文挑战第6天】函数提升和变量提升是 JavaScript 语言的重要特性,但它们也可能带来一些困惑和潜在的问题。通过深入理解和掌握它们的原理和表现,开发者可以更好地编写和维护 JavaScript 代码,避免因不了解这些机制而导致的错误和不一致。同时,不断提高对执行上下文等相关概念的认识,将有助于提升对 JavaScript 语言的整体理解和运用能力。
【javaScript数组,函数】的基础知识点
【javaScript数组,函数】的基础知识点
56 5
js中函数、方法、对象的区别
js中函数、方法、对象的区别
68 2

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等