一文掌握: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 或优化思路,欢迎留言讨论~


相关推荐
北'辰31 分钟前
DeepSeek智能考试系统智能体
前端·后端·架构·开源·github·deepseek
前端历劫之路1 小时前
🔥 1.30 分!我的 JS 库 Mettle.js 杀入全球性能榜,紧追 Vue
前端·javascript·vue.js
在未来等你1 小时前
RabbitMQ面试精讲 Day 16:生产者优化策略与实践
中间件·面试·消息队列·rabbitmq
爱敲代码的小旗2 小时前
Webpack 5 高性能配置方案
前端·webpack·node.js
Murray的菜鸟笔记2 小时前
【Vue Router】路由模式、懒加载、守卫、权限、缓存
前端·vue router
苏格拉没有底了3 小时前
由频繁创建3D火焰造成的内存泄漏问题
前端
阿彬爱学习3 小时前
大模型在垂直场景的创新应用:搜索、推荐、营销与客服新玩法
前端·javascript·easyui
我是哪吒3 小时前
分布式微服务系统架构第164集:架构懂了就来了解数据库存储扩展千亿读写
后端·面试·github
UrbanJazzerati3 小时前
PowerShell 自动化实战:自动化为 Git Staged 内容添加 Issue 注释标记
后端·面试·shell
橙序员小站3 小时前
通过trae开发你的第一个Chrome扩展插件
前端·javascript·后端