手写实现30个数组原生API,全面剖析数组操作原理
2023-10-17 16:27:48
深入浅出剖析 JavaScript 数组 API 及其底层实现
在 JavaScript 中,数组是一种至关重要的数据结构,它以有序序列存储元素。它提供了丰富的原生方法,用于处理数据,从而简化了开发人员的任务。然而,仅仅了解这些方法的语法是不够的。要掌握数组,我们必须深入了解其底层实现原理。
本文将逐一介绍 30 个常用的数组 API,深入解析它们的用途、实现思路和代码。准备好大开眼界吧!
数组的常用 API
1. Array.isArray()
function isArray(value) {
return value instanceof Array;
}
这个方法检查一个值是否是一个数组。它使用 instanceof
操作符,该操作符检查一个值是否属于某个类。
2. Array.from()
function from(arrayLike) {
const result = [];
for (let i = 0; i < arrayLike.length; i++) {
result.push(arrayLike[i]);
}
return result;
}
这个方法将一个类数组对象(如 arguments 对象)转换为一个真正的数组。它遍历类数组对象,依次将元素推入结果数组中。
3. Array.of()
function of(...elements) {
return elements;
}
这个方法创建一个新的数组,其中包含传递给它的所有元素。与 new Array()
不同,它不需要我们指定数组的长度。
4. Array.prototype.concat()
Array.prototype.concat = function() {
const result = this.slice();
for (let i = 0; i < arguments.length; i++) {
const item = arguments[i];
if (Array.isArray(item)) {
result.push(...item);
} else {
result.push(item);
}
}
return result;
};
这个方法将数组与其他数组或元素连接起来。它创建一个新数组,并将原始数组与传入的参数连接起来。如果参数是一个数组,它的元素也会被连接起来。
5. Array.prototype.join()
Array.prototype.join = function(separator) {
let result = "";
for (let i = 0; i < this.length; i++) {
result += this[i];
if (i < this.length - 1) {
result += separator;
}
}
return result;
};
这个方法将数组的元素连接成一个字符串。它接受一个可选的分隔符作为参数,默认情况下是逗号。
6. Array.prototype.pop()
Array.prototype.pop = function() {
const lastIndex = this.length - 1;
const lastItem = this[lastIndex];
this.length = lastIndex;
return lastItem;
};
这个方法从数组的末尾删除并返回最后一个元素。它更新数组的长度,以反映删除。
7. Array.prototype.push()
Array.prototype.push = function(...items) {
for (let i = 0; i < items.length; i++) {
this[this.length] = items[i];
this.length++;
}
};
这个方法将一个或多个元素添加到数组的末尾。它更新数组的长度,以反映添加。
8. Array.prototype.shift()
Array.prototype.shift = function() {
const firstItem = this[0];
for (let i = 1; i < this.length; i++) {
this[i - 1] = this[i];
}
this.length--;
return firstItem;
};
这个方法从数组的开头删除并返回第一个元素。它更新数组的长度,以反映删除,并重新索引剩余元素。
9. Array.prototype.unshift()
Array.prototype.unshift = function(...items) {
for (let i = this.length + items.length - 1; i >= items.length; i--) {
this[i] = this[i - items.length];
}
for (let i = 0; i < items.length; i++) {
this[i] = items[i];
}
this.length += items.length;
};
这个方法将一个或多个元素添加到数组的开头。它更新数组的长度,以反映添加,并重新索引剩余元素。
10. Array.prototype.reverse()
Array.prototype.reverse = function() {
for (let i = 0; i < this.length / 2; i++) {
const temp = this[i];
this[i] = this[this.length - i - 1];
this[this.length - i - 1] = temp;
}
};
这个方法反转数组中元素的顺序。它使用一个循环将元素成对交换,直到中间。
11. Array.prototype.sort()
Array.prototype.sort = function(compareFunction) {
if (!compareFunction) {
compareFunction = function(a, b) {
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
};
}
for (let i = 0; i < this.length; i++) {
for (let j = i + 1; j < this.length; j++) {
if (compareFunction(this[i], this[j]) > 0) {
const temp = this[i];
this[i] = this[j];
this[j] = temp;
}
}
}
};
这个方法对数组中的元素进行排序。它接受一个可选的比较函数,如果省略,则使用默认的比较函数,该函数将两个元素进行比较并返回 -1(小于)、0(等于)或 1(大于)。它使用冒泡排序算法对数组进行排序。
12. Array.prototype.slice()
Array.prototype.slice = function(start, end) {
const result = [];
if (start < 0) {
start = this.length + start;
}
if (end < 0) {
end = this.length + end;
}
for (let i = start; i < end && i < this.length; i++) {
result.push(this[i]);
}
return result;
};
这个方法从数组中提取一个子数组。它接受两个参数:开始索引(可选,默认为 0)和结束索引(可选,默认为数组的长度)。它返回一个包含从开始索引到结束索引之间所有元素的新数组(不包括结束索引)。
13. Array.prototype.splice()
Array.prototype.splice = function(start, deleteCount, ...items) {
const deletedItems = this.slice(start, start + deleteCount);
for (let i = start + deleteCount; i < this.length; i++) {
this[i - deleteCount] = this[i];
}
this.length -= deleteCount;
for (let i = this.length; i < this.length + items.length; i++) {
this[i] = items[i - this.length];
}
this.length += items.length;
return deletedItems;
};
这个方法从数组中添加、删除或替换元素。它接受三个参数:开始索引、要删除的元素数(可选,默认为 0)和要添加的元素。它返回一个包含已删除元素的新数组。
14. Array.prototype.forEach()
Array.prototype.forEach = function(callbackFn) {
for (let i = 0; i < this.length; i++) {
callbackFn(this[i], i, this);
}
};
这个方法对数组中的每个元素执行一个给定的回调函数。它接受一个回调函数作为参数,该函数接收三个参数:元素本身、元素的索引和数组本身。
15. Array.prototype.map()
Array.prototype.map = function(callbackFn) {
const result = [];
for (let i = 0; i < this.length; i++) {
result.push(callbackFn(this[i], i, this));
}
return result;
};
这个方法将数组中的每个元素映射到一个新数组中。它接受一个回调函数作为参数,该函数接收三个