JS 常用数组方法封装(包含splice)

数组基本操作方法

以下方法均改变原数组,需要操作数组的 length 属性

Push

  • 返回值:新数组的长度
  • 思路:数组的长度等于 arguments[i]
Array.prototype.myPush = function () {
    for (let i = 0; i < arguments.length; i++) {
        this[this.length] = arguments[i];
    }
    return this.length;
};

Pop

  • 返回值:删除的项(如果空数组,返回 undefined)
  • 思路:让数组长度 -1
Array.prototype.myPop = function () {
    return this.length==0?undefined:(this[this.length - 1],this.length--);
};

Shift

  • 返回值:删除的项
  • 思路:让数组前一个值 this[i] 等于后一个值 this[i + 1] ,之后把数组长度 -1
Array.prototype.myShift = function () {
    if (this.length == 0) {
        return;
    }
    let del = this[0];
    for (let i = 0; i < this.length; i++) {
        this[i] = this[i + 1];
    }
    this.length--;
    return del;
};

Unshift

  • 返回值:新数组的长度
  • 思路:让数组后一个值 this[i] 等于前 n(n=arguments.length)个值 this[i - arguments.length] ,之后把前 n 个值填为 arguments[i]
Array.prototype.myUnshift = function () {
    this.length += arguments.length;
    for (let i = this.length - 1; i >= 0; i--) {
        if (i >= arguments.length) {
            this[i] = this[i - arguments.length];
        } else {
            this[i] = arguments[i];
        }
    }
    return this.length;
};
  • ES6 方法实现能简单一些。其实就是拼接数组,之后把拼接的数组一项一项赋值给原数组
Array.prototype.myUnshift = function (...arg) {
    var newArr = [...arg, ...this];
    for (let i = 0; i < newArr.length; i++) {
        this[i] = newArr[i];
    }
    return this.length;
};

数组操作方法

以下方法除splice(改变原数组)均不改变原数组

splice(特殊)

因为 push 实现比较简单,这里用到了 push 方法,能简写一两行

  • 返回值:删除的项(数组)

  • 思路:按参数数量分别进行判定

    • 参数小于等于1个,从 start 开始添加到新数组,并把添加那项删除(数组长度也减少)
    • 参数大于1个,先进行删除(跟上一步相同)再把数组分成三份,左边+中间被替换的项+右边,合并数组

    注意:

    1. 第一个参数为负数:如果转换为正数,大于数组长度,直接转换为0;小于等于数组长度,需加上数组长度
    2. 第二个参数:如果小于0,直接转换为0
    3. 第三个参数起:要添加的项
Array.prototype.mySplice = function (start, del) {
    let arr = [];
    if (start < 0) {
        start = -start > this.length ? 0 : this.length + start;
    }
    if (arguments.length <= 1) {
        for (let i = start; i < this.length; i++) {
            arr.push(this[i]);
        }
        this.length = start;
    } else {
        del = del < 0 ? 0 : del;
        // 删除数组这一步
        for (let i = 0; i < del; i++) {
            arr.push(this[start + i]);
            this[start + i] = this[start + i + del];
        }
        this.length -= del;
        let lArr = [];
        for (let i = 0; i < start; i++) {
            lArr.push(this[i]);
        }
        for (let i = 0; i < arguments.length - 2; i++) {
            lArr.push(arguments[i + 2]);
        }
        for (let i = start; i < this.length; i++) {
            lArr.push(this[i]);
        }
        for (let i = 0; i < lArr.length; i++) {
            this[i] = lArr[i];
        }
    }
    return arr;
};
  • 删除数组那一步,我第一时间想到的是冒泡(把删除项一次一次冒到最后一位),最后出来的代码是下面这样(非常麻烦)
let that = del;
for (let i = that; i > 0; i++) {
    if (that <= 0) {
        break;
    }
    for (let j = start; j < this.length - 1; j++) {
        [this[j], this[j + 1]] = [this[j + 1], this[j]];
    }
    arr.push(this[this.length - 1]);
    this.length--;
    that--;
}
  • 大可不必这样,把删除项的下一位(不删除)往前挪一个一个覆盖要删除的项即可
for (let i = 0; i < del; i++) {
    arr.push(this[start + i]);
    this[start + i] = this[start + i + del];
}
this.length -= del;

concat

  • 返回值:拼接后的新数组
  • 思路:如果参数是数组需遍历后一个一个添加到新数组
Array.prototype.myConcat = function () {
    let arr = [];
    for (let i = 0; i < this.length; i++) {
        arr[i] = this[i];
    }
    for (let i = 0; i < arguments.length; i++) {
        const el = arguments[i];
        if (Array.isArray(el)) {
            for (let i = 0; i < el.length; i++) {
                arr[arr.length] = el[i];
            }
        } else {
            arr[arr.length] = el;
        }
    }
    return arr;
};

slice

  • 返回值:复制后的新数组
  • 思路:如果传参是负数索引,需对其长度进行判定。如果大于数组长度,将其改为0;小于数组长度,将其改为arr.length+(负数索引)
Array.prototype.mySlice = function (start = 0, end = this.length) {
    var arr = [];
    if (start < 0) {
        start = -start > this.length ? 0 : this.length + start;
    }
    if (end < 0) {
        end = -end > this.length ? 0 : this.length + end;
    }
    for (let i = start; i < end; i++) {
        arr.push(this[i]);
    }
    return arr;
};

flat

  • 返回值:扁平后的新数组
  • 思路:递归(下面实现没有加上可以指定递归深度的参数,类似arr.flat(Infinity)
Array.prototype.myFlat = function () {
    let arr = [];
    fn(this);
    function fn(ary) {
        for (let i = 0; i < ary.length; i++) {
            const item = ary[i];
            if (Array.isArray(item)) {
                fn(item);
            } else {
                arr.push(item);
            }
        }
    }
    return arr;
};

Array.prototype.myFlat = function () {
    return this.toString().split(",").map((item) => Number(item));
};

数组重排方法

reverse

  • 返回值:倒序后的数组
  • 思路:第n个数和倒数第n个数两两对换
Array.prototype.myReverse = function () {
    for (let i = 0, j = this.length - 1; j > i; i++, j--) {
        var temp = this[i];
        this[i] = this[j];
        this[j] = temp;
    }
    return this;
};

sort

  • 返回值:排序后的数组
  • 思路:不传参的时候,两两比较 String(xxx) 的值;传参的时候判断 callBack(a-b) 是否大于 0 即可
Array.prototype.mySort = function (callBack) {
    if (this.length <= 1) {
        return this;
    }
    if (typeof callBack === "function") {
        for (let i = 0; i < this.length - 1; i++) {
            for (let j = 0; j < this.length - 1 - i; j++) {
                if (callBack(this[j], this[j + 1]) > 0) {
                    [this[j], this[j + 1]] = [this[j + 1], this[j]];
                }
            }
        }
    } else if (typeof callBack === "undefined") {
        for (let i = 0; i < this.length - 1; i++) {
            for (let j = 0; j < this.length - 1 - i; j++) {
                if (String(this[j]) > String(this[j + 1])) {
                    [this[j], this[j + 1]] = [this[j + 1], this[j]];
                }
            }
        }
    } else {
        return "参数异常";
    }
    return this;
};

数组位置方法

以下方法均不改变原数组

indexOf

  • 返回值:索引/-1
  • 思路:遍历数组,第二个参数是从哪个索引开始。如果不传参,从头查到尾部
Array.prototype.myIndexOf = function (val, index = 0) {
    if (index < 0) {
        index = -index > this.length ? 0 : index + this.length;
    }
    for (let i = index; i < this.length; i++) {
        if (this[i] === val) {
            return i;
        }
    }
    return -1;
};

lastIndexOf

  • 返回值:索引/-1
  • 思路:遍历数组,第二个参数是到哪个索引结束(从0开始到这个索引结束)。如果不传参,从头查到尾部
Array.prototype.myLastIndexOf = function (val, index = this.length) {
    if (index < 0) {
        index = -index >= this.length ? 0 : index + this.length;
    }
    for (let i = index; i >= 0; i--) {
        if (this[i] === val) {
            return i;
        }
    }
    return -1;
};

includes

  • 返回值:true/false
  • 思路:遍历数组
Array.prototype.myIncludes = function (val) {
    for (let i = 0; i < this.length; i++) {
        if (this[i] === val) {
            return true;
        }
    }
    return false;
};

数组迭代方法

以下方法均不改变原数组

forEach

回调函数内部 this 一般指向 window

  • 返回值:undefined
  • 思路:遍历数组
Array.prototype.myForEach = function (callBack) {
    for (let i = 0; i < this.length; i++) {
        let index = i, item = this[i];
        callBack(item, index);
    }
};

map

  • 返回值:映射后的新数组
  • 思路:遍历数组,把数组每以项经过运算后赋值给新数组
Array.prototype.myMap = function (callBack) {
    let arr = [];
    for (let i = 0; i < this.length; i++) {
        let index = i, item = this[i];
        arr[i] = callBack(item, index);
    }
    return arr;
};

reduce

  • 返回值:函数累计处理的结果
  • 思路:initial 返回值在数组的每次迭代中被记住,最后成为最终的结果值
Array.prototype.myReduce = function (callBack, initial) {
    if (typeof callBack !== "function") throw new TypeError("callBack must be function");
    let i = 0;
    if (typeof initial === "undefined") {
        initial = this[0];
        i = 1;
    }
    for (; i < this.length; i++) {
        initial = callBack(initial, this[i], i)
    }
    return initial;
};

find

  • 返回值:找到就返回符合的元素,没有返回 undefined
  • 思路:遍历数组
Array.prototype.myFind = function (callBack) {
    for (let i = 0; i < this.length; i++) {
        if (callBack(this[i], i)) return this[i]
    }
}

every

  • 返回值:只要有一个不符合返回false,如果都符合返回 true
  • 思路:遍历数组,一假即假
Array.prototype.myEvery = function (callBack) {
    for (let i = 0; i < this.length; i++) {
        if (!callBack(this[i], i)) return false
    }
    return true
}

some

  • 返回值:只要有一个符合就返回 true,如果都符合返回 false
  • 思路:遍历数组,一真即真
Array.prototype.mySome = function (callBack) {
    for (let i = 0; i < this.length; i++) {
        if (callBack(this[i], i)) return true
    }
    return false
}

filter

  • 返回值:一个新数组,数组里面是符合条件的所有元素
  • 思路:遍历数组
Array.prototype.myFilter = function (callBack) {
    if (!Array.isArray(this) || !this.length || typeof callback !== 'function') {
        return []
    }
    let arr = [];
    for (let i = 0; i < this.length; i++) {
        if (!callBack(this[i], i)) {
            arr.push(this[i]);
        }
    }
    return arr
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值