学无先后,达者为师

网站首页 前端文档 正文

Javascript数组常用方法重写之find,findIndex,filter,forEach

作者:懒人Ethan 更新时间: 2021-12-20 前端文档

概要

我们在前端开发过程中,经常使用到各种数组的原生方法。为了更好的理解和使用这些原生方法,所以笔者试着重写了这些方法,并实现了相同的功能。

本文主要对find,findIndex,filter,forEach这四个原型方法进行重写。

代码实现

由于新方法也要定义在原型链上,为了避免重复,所以本文参考C#的LINQ方法命名。具体如下:

原型方法名称 重写后的方法名称
find First
findIndex firstIndex
filter Where
forEach Each

find 方法重写

实现功能:在数组内找到第一个符合搜索条件的元素,并返回该元素,如果没有符合条件的元素,返回undefined。

不对原数组内元素进行修改,返回值如果是JS对象,直接返回数组内元素,不对返回值进行克隆。

Array.prototype.First = function(fn){
    var self = this;
    var length = self.length;
    var newThis = arguments[1] || window; 
    var item;   
    for(var i=0; i<length; ++i){
        item = deepClone(self[i]);
        var res = fn.apply(newThis,[item, i, self]);
        if (res){
            return self[i];
        }
    }
    return;
}
  1. 和JS原生的find方法一样,固定参数只有一个,类型为Fucntion,该方法返回一个bool值。
  2. 根据ES5的this使用规则,谁调用该方法,该方法内的this指向谁,所以该方法内的this指向未来调用该方法的数组对象。
  3. 和JS原生的find方法一样,First方法的第二个参数是可选的。它是新新的this,如果该参数不为空,则First方法内的this指向该对象。
  4. 遍历数组,数组元素在使用之前进行深度克隆,避免使用中被篡改,deepClone方法详见附录。
  5. 调用传入fn方法,检查传入的元素是否满足搜索条件。其中,fn方法的每个参数都是可选的,并且需要固定fn方法内的this,所以采用apply方法进行调用。
  6. 找到第一个符合搜索条件的元素后立刻返回。

findIndex 方法重写

实现功能:在数组内找到第一个符合搜索条件的元素,并返回该元素的索引,如果没有符合条件的元素,返回 -1。

不对原数组内元素进行修改,返回值如果是JS对象,直接返回数组内元素,不对返回值进行克隆。

Array.prototype.FirstIndex = function(fn){
    var self = this;
    var length = self.length;
    var newThis = arguments[1] || window; 
    var item;   
    for(var i=0; i<length; ++i){
        item = deepClone(self[i]);
        var res = fn.apply(newThis,[item, i, self]);
        if (res){
            return i;
        }
    }
    return -1;
}
  1. 和JS原生的findIndex方法一样,固定参数只有一个,类型为Fucntion,该方法返回一个bool值。
  2. 根据ES5的this使用规则,谁调用该方法,该方法内的this指向谁,所以该方法内的this指向未来调用该方法的数组对象。
  3. 和JS原生的findIndex方法一样,FirstIndex方法的第二个参数是可选的。它是新新的this,如果该参数不为空,则FirstIndex方法内的this指向该对象。
  4. 遍历数组,数组元素在使用之前进行深度克隆,避免使用中被篡改,deepClone方法详见附录。
  5. 调用传入fn方法,检查传入的元素是否满足搜索条件。其中,fn方法的每个参数都是可选的,并且需要固定fn方法内的this,所以采用apply方法进行调用。
  6. 找到第一个符合搜索条件的元素后立刻返回该元素的索引。

filter 方法重写

实现功能:在数组内找到第全部符合搜索条件的元素,并返以数组的形式返回所有符合条件的元素,如果没有符合条件的元素,返回空数组。

不对原数组内元素进行修改,返回值如果是JS对象,直接返回数组内元素,不对返回值进行克隆。

Array.prototype.Where = function(fn){
    var self = this;
    var length = self.length;
    var newThis = arguments[1] || window; 
    var res = [];
    var item;
    for(var i=0; i<length; ++i){
        item = deepClone(self[i]);
        var filter = fn.apply(newThis,[item, i, self]);
        filter && res.push(self[i]);
    }
    return res;
}
  1. 和JS原生的filter方法一样,固定参数只有一个,类型为Fucntion,该方法返回一个bool值。
  2. 根据ES5的this使用规则,谁调用该方法,该方法内的this指向谁,所以该方法内的this指向未来调用该方法的数组对象。
  3. 和JS原生的filter方法一样,Where方法的第二个参数是可选的。它是新新的this,如果该参数不为空,则Where方法内的this指向该对象。
  4. 遍历数组,数组元素在使用之前进行深度克隆,避免使用中被篡改,deepClone方法详见附录。
  5. 调用传入fn方法,检查传入的元素是否满足搜索条件,满足条件的放入返回数组中。其中,fn方法的每个参数都是可选的,并且需要固定fn方法内的this,所以采用apply方法进行调用。

forEach方法重写

实现功能:遍历数组内每个元素,并执行传入的方法,无返回值。不对原数组内元素进行修改。

Array.prototype.Each = function(fn){
    var self = this;
    var length = self.length;
    var newThis = arguments[1] || window; 
    var item;
    for(var i=0; i<length; ++i){
        item = deepClone(self[i]);
        fn.apply(newThis, [item, i, self]);
    }
    return;
}
  1. 和JS原生的filter方法一样,固定参数只有一个,类型为Fucntion,该方法无返回值。
  2. 根据ES5的this使用规则,谁调用该方法,该方法内的this指向谁,所以该方法内的this指向未来调用该方法的数组对象。
  3. 和JS原生的forEach方法一样,Each方法的第二个参数是可选的。它是新新的this,如果该参数不为空,则方法内的this指向该对象。
  4. 遍历数组,数组元素在使用之前进行深度克隆,避免使用中被篡改,deepClone方法详见附录。
  5. 调用传入fn方法,检查传入的元素是否满足搜索条件,满足条件的放入返回数组中。其中,fn方法的每个参数都是可选的,并且需要固定fn方法内的this,所以采用apply方法进行调用。

附录

function deepClone(origin, map = new WeakMap()){
    if (origin == undefined || typeof origin !== "object"){
        return origin;
    }
    if (origin instanceof Date){
        return new Date(origin);
    }
    if (origin instanceof RegExp){
        return new RegExp(origin);
    }
    var copied = map.get(origin);
    if (!!copied){
        return copied;
    }
    let target = new origin.constructor();
    map.set(origin, target);
    let keys = Reflect.ownKeys(origin);
    for(let key of keys){  
        target[key] = deepClone(origin[key], map);
    }
    return target;
} 

原文链接:https://blog.csdn.net/weixin_43263355/article/details/122088638

栏目分类
最近更新