最近经常看到如何实现原生方法的文章,之前自己对于这些并没有特别在意,看了几篇之后发现还是挺有意思的,搞清楚其中的原理比业务代码有趣多了。今天来记录一下数组的map和filter方法
参考资料:
Array.prototype.myMap
在实现map方法之前,有一个要注意的地方在于,map方法有一个很少用到的第二个参数,作为回调函数的作用域对象。即
arr.map(fn(item, index, arr) => {}, obj)
中的obj
。虽然平时用得少,但是实现的时候要记得考虑进去。
// 一般实现
Array.prototype.myMap = function() {
let arr = this;
let result = [];
let [fn, obj] = Array.prototype.slice.call(arguments);
if (!arr instanceof Array) {
throw new TypeError('Array only!');
}
if (typeof fn !== 'function') {
throw new TypeError(`${fn} is not a function!`);
}
for (let i = 0; i < arr.length; i++) {
const item = fn.call(obj, arr[i], i, arr);
result.push(item);
}
return result
}
// reduce高端实现
Array.prototype.redecuMap = function(fn, thisArg) {
return (list) => {
// 不怎么愿意写下面这两个判断条件
if (typeof fn !== 'function') {
throw new TypeError(fn + 'is not a function')
}
if (!Array.isArray(list)) {
throw new TypeError('list must be a Array')
}
if (list.length === 0) return []
return list.reduce((acc, value, index) => {
return acc.concat([ fn.call(thisArg, value, index, list) ])
}, [])
}
}
// 上边是个高阶函数,返回的是另一个函数,所以调用时要这样:
reduceMap(x => x + 1)([ 1, 2, 3 ]) // [ 2, 3, 4 ]
const mapAry1 = reduceMap(function(item) {
console.log(this)
return item + 1
}, { msg: 'mapping' })([ 1, 2, 3 ])
// [ 2, 3, 4 ]
// logging { msg: 'mapping' } three times
Array.prototype.myFilter
与
map
类似的,filter
也有第二个参数,实现了map
后其他也基本没难度了。
// 一般实现
Array.prototype.myFilter = function() {
let arr = this;
let result = [];
let [fn, obj] = Array.prototype.slice.call(arguments);
if (!arr instanceof Array) {
throw new TypeError('Array only!');
}
if (typeof fn !== 'function') {
throw new TypeError(`${fn} is not a function!`);
}
for (let i = 0; i < arr.length; i++) {
const validate = fn.call(obj, arr[i], i, arr);
if(validate) {
result.push(arr[i]);
}
}
return result
}
// redece高端实现
Array.prototype.reduceFilter = function(fn, thisArg) {
return (list) => {
if (typeof fn !== 'function') {
throw new TypeError(fn + 'is not a function')
}
if (!Array.isArray(list)) {
throw new TypeError('list must be a Array')
}
if (list.length === 0) return []
return list.reduce((acc, value, index) => {
const validate = fn.call(thisAry, value, index, list);
return validate ? acc.concat([ value ]) : acc
}, [])
}
}
// 上边是个高阶函数,返回的是另一个函数,所以调用时要这样:
reduceFilter(x => x % 2 === 0)([ 1, 2, 3 ]) // [ 2 ]