从头开始实现 JavaScript 数组方法
目录
介绍
JavaScript Array 类是一个全局对象,用于构造数组。Array 是一种特殊类型的可变对象,用于存储多个值。
在本文中,我们将从头开始实现我们自己的数组方法。这些实现并非旨在取代现有的方法,而是为了更好地理解这些方法的工作原理及其用途。
方法 | 描述 |
---|---|
索引() | 返回数组中给定元素的第一个索引,否则返回 -1。 |
lastIndexOf() | 返回数组中给定元素的最后一个索引,否则返回 -1。 |
撤销() | 返回反转的数组。 |
forEach() | 为每个数组元素执行一次提供的函数。 |
地图() | 使用对调用数组中每个元素调用提供的函数的结果来创建一个新数组。 |
筛选() | 创建一个新数组,其中包含通过所提供函数实现的测试的所有元素。 |
减少() | 对累加器和数组中的每个元素应用一个函数,以将其减少为单个值。 |
为了更好地理解高阶函数及其具体方法map()
,您可以查看这篇文章。filter()
reduce()
在开始实施这些方法之前,我们将快速了解一下它们如何prototype
工作this
。
什么是原型?
在 JavaScript 中,每个函数和对象默认都有一个名为“prototype”的属性。原型是 JavaScript 对象相互继承方法和属性的机制。当我们想要为一个对象添加新属性,并在所有实例之间共享时,原型非常有用。
function User () {
this.name = 'George',
this.age = 23
}
User.prototype.email = 'george@email.com';
User.prototype.userInfo = function () {
console.log('[User name]: ', this.name, ' [User age]: ', this.age);
}
const user = new User();
console.log(user.email); // george@email.com
user.userInfo(); // [User name]: George [User age]: 23
在上面的例子中,我们创建了User
具有属性name
和 的函数对象age
。然后,我们访问User
具有 属性 的函数对象prototype
,并将 属性email
和 函数添加userInfo()
到其中。
这是什么?
的值由当前拥有该关键字所在this
空间的对象决定(运行时绑定)。this
function User () {
this.name = 'George',
this.age = 23,
this.printInfo = function() {
console.log(this);
}
this.orders = {
orderId: '12345',
printOrderId: function() {
console.log(this);
}
}
}
const user = new User();
user.printInfo(); // User { name: 'George', age: 23, printInfo: [Function], orders: { orderId: '12345', printOrderId: [Function: printOrderId] } }
user.orders.printOrderId(); // { orderId: '12345', printOrderId: [Function: printOrderId] }
在上面的例子中,我们再次使用函数对象User
并将该对象添加orders
到其中。user.printInfo()
打印出该this
值,在本例中,它包含函数对象的所有属性User
。user.orders.printOrderId()
只打印对象的属性orders
,这是因为方法printOrderId()
是通过orders
对象调用的。
让我们实现数组方法
为了实现这些方法,我们将Array
通过prototype
属性访问对象,然后添加新的方法。this
方法中的关键字 具有调用相应数组方法的数组的值。
自定义 indexOf
Array.prototype.customIndexOf = function (value) {
for (let i = 0; i < this.length; i++) {
if (this[i] == value)
return i;
}
return -1;
}
const output = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(output.customIndexOf(2)); // 1
在上面的例子中,该customIndexOf
方法将一个值作为参数,然后我们迭代数组直到找到相应的值并返回其索引。
自定义 lastIndexOf
Array.prototype.customLastIndexOf = function (value) {
for (let i = this.length - 1; i >= 0; i--) {
if (this[i] == value)
return i;
}
return -1;
}
const output = [1, 2, 3, 4, 5, 9, 7, 9, 9, 10];
console.log(output.customLastIndexOf(9)); // 8
在上面的例子中,该customLastIndexOf
方法将一个值作为参数,然后我们迭代数组,直到找到最后一个对应的值并返回其索引。
自定义反向
Array.prototype.customReverse = function () {
let left = 0;
let right = this.length - 1;
while(left < right) {
let temp = this[left];
this[left] = this[right];
this[right] = temp;
left++;
right--;
}
return this;
}
const output = [1, 'b', 'abc', { name: 'Jonh' }, 10];
console.log(output.customReverse()); // [10, { name: 'Jonh' }, 'abc', 'b', 1]
在上面的例子中,该customReverse
方法将数组反转并返回它。
自定义 forEach
Array.prototype.customForEach = function (callback) {
for (let i = 0; i < this.length; i++) {
callback(this[i], i, this);
}
}
const output = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
output.customForEach(elem => {
console.log(elem);
}); // 1 2 3 4 5 6 7 8 9 10
在上面的例子中,该customForEach
方法将一个回调函数作为参数,并将其应用于数组中的每个元素。此外,回调函数还会接收索引和数组本身,以便在需要时使用。
自定义地图
Array.prototype.customMap = function map(callback) {
const results = [];
for (let i = 0; i < this.length; i++) {
results.push(callback(this[i], i, this));
}
return results;
}
let output = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
output = output.customMap(elem => {
return 3*elem;
});
console.log(output); // [ 3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
在上面的例子中,该customMap
方法将一个回调函数作为参数,对于数组中的每个元素,我们都调用该回调函数,并将结果返回到一个新的数组中。同样,回调函数还会接收索引和数组本身,以便在需要时使用。
自定义过滤器
Array.prototype.customFilter = function (callback) {
const results = [];
for (let i = 0; i < this.length; i++) {
if(callback(this[i], i, this))
results.push(this[i]);
}
return results;
}
let output = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
output = output.customFilter((elem) => {
return elem % 2 === 0;
});
console.log(output); // [ 2, 4, 6, 8, 10 ]
在上面的例子中,该customFilter
方法将回调函数作为参数,对于数组中的每个元素,我们都应用回调函数,对于传递回调函数的值,我们将结果返回到新数组中。
自定义减少
Array.prototype.customReduce = function (callback, initialValue) {
let value = initialValue;
for (let i = 0; i < this.length; i++) {
value = callback(value, this[i]);
}
return value;
}
const output = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const sum = output.customReduce((acc = 0, elem) => {
return acc + elem;
});
console.log(sum); // 55
在上面的例子中,该customReduce
方法将回调函数和累加器变量作为参数,我们将回调函数应用于数组中每个元素的累加器,直到将其减少为单个值。
您可以在此处查看我的 github 存储库。