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

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

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

这篇文章面向那些已经熟练使用for循环,但对Array.mapArray.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]

接下来我们将这个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]

现在我们继续深化这个抽象思路,将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]

这样有什么好处呢?设想如果我们想对每一个元素乘以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;
}

重构为:

function multiply(arr, multiplyFunction) {
    var newArr = [];

    for(var i = 0; i < arr.length; i++) {
        newArr[i] = multiplyFunction(arr[i]);
    }
    return newArr;
}

我们将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]

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

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]

Map

我们进一步抽象:

function multiply(arr, multiplyFunction) {
    var newArr = [];

    for(var i = 0; i < arr.length; i++) {
        newArr[i] = multiplyFunction(arr[i]);
    }
    return newArr;
}

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;
}

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

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

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]

如果使用自带的Array.map函数,则如下所示:

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

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‘]

因此,你可以再变换函数中使用索引和原始的数组。比如:你想要将一个列表变为带序号的列表,则需要使用索引(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"]

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

function map(arr, transform) {
    var newArr = [];

    for(var i = 0; i < arr.length; i++) {
        newArr[i] = transform(arr[i], i, arr);
    }
    return newArr;
}

当然,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]

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

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]

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

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]

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

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];

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

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

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;
}

这就是一个基本的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‘]

同样,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‘]

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了7亿+错误事件,得到了Google、360、金山软件、百姓网等众多知名用户的认可。欢迎免费试用!

版权声明

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

原文地址:http://blog.51cto.com/13957060/2318624

时间: 2024-10-16 03:29:59

如何实现JavaScript的Map和Filter函数?的相关文章

Javascript学习之Map和Filter函数实现方法详解

本文和大家分享的主要是JavaScript的Map和Filter函数的实现相关内容及其工作原理,一起来看看吧,希望对大家学习javascript有所帮助. Array.map Array.map通过对输入的数组中每一个元素进行变换,返回由变换后的元素按序组成的新数组.原始数组的值不会被修改.假设我们相对一个数组中的每一个元素乘以3,使用for循环可以这样写. for循环 var originalArr = [1, 2, 3, 4, 5];var newArr = [];for(var i = 0

python的 map和filter函数

一, map     #基本的map运用都可以用解析去替代,复杂的仍然需要定义函数,利用map去做 map(函数, 序列) 将序列的各项经过函数处理, 然后返回到一个新列表中. #itertools.imap() >>> s['a', 'b', 'c', 'd'] >>> exp1 = map(ord, s)      #s 也可以是字符串, 元组, 字典>>> exp1[97, 98, 99, 100] 序列的个数根据前面的函数而定, ord()一次

JavaScript Array --&gt;map()、filter()、reduce()、forEach()函数的使用

题目: 1.得到 3000 到 3500 之内工资的人. 2.增加一个年龄的字段,并且计算其年龄. 3.打印出每个人的所在城市 4.计算所有人的工资的总和. 测试数据: function getData() { var arr = [{ id: 1, name: 'ohzri', birth: '1999.09.09', city: '湖北', salary: 9379 }, { id: 2, name: 'rqgfd', birth: '1999.10.28', city: '湖北', sal

javascript利用map,every,filter,some,reduce,sort对数组进行最优化处理

案例: var scoresTable=[ {id:11,name:"小张",score:80}, {id:22,name:"小王",score:95}, {id:33,name:"小李",score:50}, {id:44,name:"小刘",score:65}, {id:55,name:"小徐",score:84} ] 1.快速获取最高score值(采用map,Max.sum和apply) var sc

Python一个有意思的地方:reduce、map、filter

今天阅读了关于Python函数式编程的系列文章,地址在这里: http://www.cnblogs.com/huxi/archive/2011/06/24/2089358.html 里面提到了四个内建迭代函数:reduce.map.filter.zip.其中zip是供同时迭代多个迭代器用的,这里就不讨论了.主要讨论剩下的三个. 我发现一个有意思的事情,就是剩下的三个函数,reduce.map和filter,三者可以相互转换.例如以reduce为基础,可以实现map和filter函数如下: 1 d

JavaScript中map函数和filter的简单举例(转)

js的数组迭代器函数map和filter,可以遍历数组时产生新的数组,和python的map函数很类似1)filter是满足条件的留下,是对原数组的过滤:2)map则是对原数组的加工,映射成一一映射的新数组var xx = [1, 2, 5, 7];function pp(x){return x % 2;}function px(x){return x % 2;}var m = xx.map(pp);console.log("m = " + m);var f = xx.filter(p

JavaScript实现Map、Reduce和Filter

1. [代码][JavaScript]代码     <script type="text/javascript">// 函数式编程:// 描述我们要做什么,而不是我们如何去做.这意味着我们工作在一个更高的抽象层次.函数式编程将导致更精巧.清晰和令人愉快的代码. // 最基础的forEachfunction forEach(array, action) {for (var i = 0; i < array.length; i++) {action(array[i]);}

Python-lambda函数,map函数,filter函数

lambda函数主要理解: lambda 参数:操作(参数). lambda语句中,冒号前是参数,可以有多个,用逗号隔开,冒号右边的返回值.lambda语句构建的其实是一个函数对象 map函数: map(function_to_apply, list_of_inputs).map函数可以把list_of_inputs内的对象依次输入到function_to_apply中进行操作. filter函数: filter(function_to_apply, list_of_inputs).Filter

Python 函数之lambda、map、filter和reduce

1.lambda函数 lambda()是Python里的匿名函数,其语法如下: lambda [arg1[, arg2, ... argN]]: expression 学习条件运算时,对于简单的 if else 语句,可以使用三元运算来表示,即: # 普通条件语句 if 1 == 1: name = 'evescn' else: name = 'gm' # 三元运算 name = 'evescn' if 1 == 1 else 'gm' 对于简单的函数,也存在一种简便的表示方式,即:lambda