一文掌握:JavaScript 数组常用方法的手写实现

本文适合正在准备面试、提升底层原理理解的前端开发者。

在日常开发中,数组是最常用的数据结构之一,JavaScript 中的 Array 原型链上提供了大量常用方法,如 pushpopmapreduce 等。掌握这些方法的使用是基本功,而深入理解其实现原理,则是进阶前端开发的必经之路。

本文将基于原生 Array.prototype,手写实现一系列常用方法,并附上详细注释与讲解,帮助大家理解每个方法背后的实现思路。


一、增删类方法

1. myPush

js 复制代码
Array.prototype.myPush = function (...args) {
    for (let index = 0; index < args.length; index++) {
        this[this.length] = args[index];
    }
    return this.length;
};

说明

  • 通过 this.length 索引向数组末尾添加元素。
  • 返回添加后的数组长度。

2. myPop

js 复制代码
Array.prototype.myPop = function () {
	if (this.length === 0) return undefined;
	const res = this[this.length - 1];
	this.length = this.length - 1;
	return res;
};

说明

  • 删除最后一个元素,通过修改 length 实现。
  • 返回被删除的元素。

3. myUnshift

js 复制代码
Array.prototype.myUnshift = function (...args) {
    const argLength = args.length;
    const len = this.length + argLength;
    this.length = len;
    for (let index = argLength; index < len; index++) {
        this[index] = this[index - argLength];
    }
    for (let index = 0; index < argLength; index++) {
        this[index] = args[index];
    }
    return len;
};

说明

  • 将现有元素整体向后偏移,再将新增元素填入前面。

4. myShift

js 复制代码
Array.prototype.myShift = function () {
    if(this.length === 0) return undefined;
    const len = this.length;
    const res = this[0];
    for(let index = 0; index < len; index++) {
        if(index >= len - 1) break;
        this[index] = this[index+1];
    }
    this.length = len - 1;
    return res;
};

说明

  • 将所有元素前移一位,并减少 length
  • 返回被删除的首元素。

5. mySlice

js 复制代码
Array.prototype.mySlice = function(startIndex = 0, endIndex = this.length) {
    if(!this.length) return [];
    startIndex = startIndex < 0 ? startIndex + this.length : startIndex;
    endIndex = endIndex < 0 ? endIndex + this.length : endIndex;
    const length = endIndex - startIndex;
    const res = [];
    for (let index = startIndex; index < endIndex; index++) {
            res.push(this[index]);
    }
    return res;
}

二、查找类方法

6. myIndexOf

js 复制代码
Array.prototype.myIndexOf = function(value, startIndex = 0) {
    let resIndex = -1;
    if(startIndex >= 0) {
        for(let index = startIndex; index < this.length; index++) {
            if(this[index] === value) {
                resIndex = index;
                break;
            }
        }
    }
    return resIndex;
};

7. myFindIndex

js 复制代码
Array.prototype.myFindIndex = function(cb) {
    let resIndex = -1;
    for(let index = 0; index < this.length; index++) {
        if(cb(this[index],index, this)) {
            resIndex = index;
            break;
        }
    }
    return resIndex;
};

8. myFind

js 复制代码
Array.prototype.myFind = function(cb) {
    let res;
    for (let index = 0; index < this.length; index++) {
        if(cb(this[index],index,this)) {
            res = this[index];
            break;
        }
    }
    return res;
};

三、遍历与转换类方法

9. myForEach

js 复制代码
Array.prototype.myforEach = function(cb) {
    for(let index = 0; index < this.length; index++) {
        cb(this[index], index, this);
    }
};

10. myMap

js 复制代码
Array.prototype.myMap = function(cb) {
    const arr = [];
    for(let index = 0; index < this.length; index++) {
        arr.push(cb(this[index], index, this));
    }
    return arr;
};

11. myFilter

js 复制代码
Array.prototype.myFilter = function(cb) {
    const arr = [];
    for(let index = 0;index< this.length; index++) {
        cb(this[index],index,this) && arr.push(this[index]);
    }
    return arr;
};

12. myEvery

js 复制代码
Array.prototype.myEvery = function(cb) {
    let flag = true;
    for(let index = 0; index < this.length; index++) {
        if(!cb(this[index],index,this)) {
            flag = false
            break;
        }
    }
    return flag;
};

13. mySome

js 复制代码
Array.prototype.mySome = function(cb) {
    let flag = false;
    for(let index = 0; index < this.length; index++) {
        if(cb(this[index],index, this)) {
            flag = true;
            break;
        }
    }
    return flag;
};

14. myReduce

js 复制代码
Array.prototype.myReduce = function(cb, initialValue) {
    const currentIndex = initialValue ? 0 : 1;
    initialValue = initialValue || this[0];
    for(let index = currentIndex;index<this.length;index++) {
        initialValue = cb(initialValue, this[index], index, this);
    }
    return initialValue;
};

说明

  • 如果未传入初始值,从第一个元素开始。
  • 可扩展为处理空数组、只传回调等边界情况。

四、其他方法实现

15. myConcat

js 复制代码
Array.prototype.myConcat = function(...args) {
    const arr = [];
    for (let index = 0; index < this.length; index++) {
        arr.push(this[index]);
    }
    if(args.length) {
        for (let index = 0; index < args.length; index++) {
            if(Array.isArray(args[index])) {
                for (let j = 0; j < args[index].length; j++) {
                    arr.push(args[index][j]);
                }
            } else {
                arr.push(args[index]);
            }
        }
    }
    return arr;
};

16. myReverse

js 复制代码
Array.prototype.myReverse = function() {
    let temp;
    for(let index = 0; index < Math.floor(this.length / 2); index++){
        temp = this[index];
        this[index] = this[this.length - 1 - index];
        this[this.length - 1 - index] = temp;
    }
    return this;
};

17. myFlat

js 复制代码
Array.prototype.myFlat = function(depth = 1) {
    let res = [];
    for(let index = 0; index < this.length; index++) {
        if(Array.isArray(this[index]) && depth > 0) {
            res = res.myConcat(this[index].myFlat(depth - 1));
        } else {
            res.push(this[index]);
        }
    }
    return res;
};

18. myIncludes

js 复制代码
Array.prototype.myIncludes = function(value, fromIndex = 0) {
    let flag = false;
    if(fromIndex < 0) {
        fromIndex = fromIndex + this.length;
    } else if(fromIndex >= this.length) {
        return flag;
    } else if(fromIndex < -this.length) {
        fromIndex = 0;
    }
    for(let index = fromIndex; index < this.length; index++){
        if(this[index] === value){
            flag = true;
            break;
        }
    }
    return flag;
};

19. myJoin

js 复制代码
Array.prototype.myJoin = function(separator = ',') {
    if(!Array.isArray(this) || typeof separator !== 'string') return;
    let str = '';
    for (let index = 0; index < this.length; index++) {
        str = str + `${index > 0 ? separator : ''}${this[index]}`
    }
    return str;
};

20. myAt

js 复制代码
Array.prototype.myAt = function(index) {
    if(!Array.isArray(this)) return;
    if(index < 0) {
        index = index + this.length;
    }
    return this[index];
};

总结

实现了 20 个常见数组方法,涵盖了新增、删除、查找、遍历、转换、拼接等常见操作。手写的过程不仅加深了对 API 的理解,也有助于提升编码与面试能力。

如你发现实现过程中的 bug 或优化思路,欢迎留言讨论~


相关推荐
卡布叻_星星1 小时前
前端JavaScript笔记之父子组件数据传递,watch用法之对象形式监听器的核心handler函数
前端·javascript·笔记
开发加微信:hedian1162 小时前
短剧小程序开发全攻略:从技术选型到核心实现(前端+后端+运营干货)
前端·微信·小程序
徐小夕@趣谈前端4 小时前
如何实现多人协同文档编辑器
javascript·vue.js·设计模式·前端框架·开源·编辑器·github
YCOSA20254 小时前
ISO 雨晨 26200.6588 Windows 11 企业版 LTSC 25H2 自用 edge 140.0.3485.81
前端·windows·edge
小白呀白5 小时前
【uni-app】树形结构数据选择框
前端·javascript·uni-app
吃饺子不吃馅5 小时前
深感一事无成,还是踏踏实实做点东西吧
前端·svg·图形学
90后的晨仔5 小时前
Mac 上配置多个 Gitee 账号的完整教程
前端·后端
PAK向日葵6 小时前
【算法导论】一道涉及到溢出处理的笔试题
算法·面试
无敌最俊朗@6 小时前
Qt 自定义控件(继承 QWidget)面试核心指南
开发语言·qt·面试
清***鞋6 小时前
转行AI产品如何准备面试
人工智能·面试·职场和发展