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


相关推荐
Zacks_xdc4 分钟前
【前端】使用Vercel部署前端项目,api转发到后端服务器
运维·服务器·前端·安全·react.js
给月亮点灯|12 分钟前
Vue基础知识-脚手架开发-使用Axios发送异步请求+代理服务器解决前后端分离项目的跨域问题
前端·javascript·vue.js
叫我阿柒啊15 分钟前
从Java全栈到前端框架:一次真实的面试对话与技术解析
java·javascript·typescript·vue·springboot·react·前端开发
张迅之1 小时前
【React】Ant Design 5.x 实现tabs圆角及反圆角效果
前端·react.js·ant-design
@CLoudbays_Martin111 小时前
为什么动态视频业务内容不可以被CDN静态缓存?
java·运维·服务器·javascript·网络·python·php
围巾哥萧尘1 小时前
Anthropic Claude for Chrome🧣
面试
蔗理苦2 小时前
2025-09-05 CSS3——盒子模型
前端·css·css3
要记得喝水2 小时前
C#某公司面试题(含题目和解析)--1
开发语言·windows·面试·c#·.net
二川bro3 小时前
第25节:VR基础与WebXR API入门
前端·3d·vr·threejs
上单带刀不带妹3 小时前
Node.js 的模块化规范是什么?CommonJS 和 ES6 模块有什么区别?
前端·node.js·es6·模块化