本文适合正在准备面试、提升底层原理理解的前端开发者。
在日常开发中,数组是最常用的数据结构之一,JavaScript 中的 Array
原型链上提供了大量常用方法,如 push
、pop
、map
、reduce
等。掌握这些方法的使用是基本功,而深入理解其实现原理,则是进阶前端开发的必经之路。
本文将基于原生 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 或优化思路,欢迎留言讨论~