介绍
JavaScript 包含多种功能来处理超出for
循环的数组,您可能已经在自己的项目中使用了这些功能,并想知道它们是如何工作的,以及为什么您会使用它们。
在本文中,您将通过创建您自己的版本的地图
、过滤
、分类
和减少
从零开始来完成。
通过将 ES6 箭头函数与 JavaScript Array 函数相结合,您可以写出非常强大、清晰的代码。
JavaScript Array 方法如何工作
让我们从一个例子开始吧. 假设您想要重复通过数组,增加每个元素一个,然后返回新的数组. 在过去,您需要做几个事情来实现这一点:
- 初始化一个新的空数组
- 重复原始数组中的每个元素
- 更改该元素并将更改的值放入新数组
代码看起来会是这样的:
1const arr = [1, 2, 3];
2const newArray = [];
3
4for (let i = 0; i < arr.length; i++) {
5 newArray[i] = arr[i] + 1;
6}
7
8return newArray;
但是,有了内置的地图
函数,你可以在一行代码中实现这一点:
1return arr.map(element => ++element);
JavaScript Array 方法大大利用 ES6 箭头函数 。
我们将涵盖的每一个数组函数都将接受一个函数作为参数,它们将通过数组的每个元素重复,并调用该函数来确定每个元素要做什么。
前提条件
要本地遵循本教程,您需要一个编辑器(如 Visual Studio Code)和一个沙盒环境扩展程序(如 Quokka.js)。
若要在線跟隨教程,您可以使用 CodePen或 CodeSandbox 。
步骤 1 - 实施地图
地图
通过每个元素迭代,以某种方式转换,将其添加到新数组中,并返回新数组。
<$>[警告] 警告:在本文中,您将用自定义功能扩展JavaScript全球对象。
JavaScript 数组函数是 Array 原型的一部分,类似于 Java 类中的函数,例如. 若要将这些函数超级,您可以将一个新的函数分配到 `Array.prototype'。
让我们创建一个新的函数,并将其分配到 Array.prototype.mapFromScratch
:
1const myCustomMapFunction = function(callback) {
2 console.log('My Custom Map Function!');
3}
4Array.prototype.mapFromScratch = myCustomMapFunction;
5
6const arr = [1, 2, 3];
7
8arr.mapFromScratch();
如果您运行此代码,您将在控制台中看到日志消息:
1[secondary_label Output]
2My Custom Map Function!
现在,添加for
循环并打印每个元素. 由于数组本身调用方法,您可以通过引用this
来访问该数组:
1const myCustomMapFunction = function(callback) {
2 console.log('My Custom Map Function!');
3
4 // 'this' refers to the array
5 for (let i = 0; i < this.length; i++) {
6 console.log(this[i]);
7 }
8
9}
现在,通过调用回调函数来执行任何所需的转换,当您这样做时,您将传递当前元素和当前索引:
1const myCustomMapFunction = function(callback) {
2 console.log('My Custom Map Function!');
3
4 // 'this' refers to the array
5 for (let i = 0; i < this.length; i++) {
6 const transformedElement = callback([this[i], i);
7 }
8
9}
最后,将转换的元素添加到新数组中,然后返回该数组。
1const myCustomMapFunction = function(callback) {
2 console.log('My Custom Map Function!');
3
4 const newArray = [];
5
6 // 'this' refers to the array
7 for (let i = 0; i < this.length; i++) {
8 newArray[i] = callback(this[i], i);
9 }
10
11 return newArray;
12}
让我们来看看你的重写函数在行动中,通过测试它与一个函数,将增加每一个值在数组:
1// arr = [1, 2, 3]
2// expected = [2, 3, 4]
3
4console.log(arr.mapFromScratch((element) => ++element));
您将获得以下输出:
1[secondary_label Output]
2My Custom Map Function!
3[2, 3, 4]
在此步骤中,您实现了自定义的地图
函数,接下来,让我们探索实现过滤器
函数。
步骤 2 - 执行过滤器
过滤
函数返回从原始数组中过滤的元素的新数组。
让我们创建一个新的函数,并将其分配到 Array.prototype.filterFromScratch
:
1const myCustomFilterFunction = function(callback) {
2 console.log('My Custom Filter Function!');
3}
4Array.prototype.filterFromScratch = myCustomFilterFunction;
5
6const arr = [1, 2, 3];
7
8arr.filterFromScratch();
现在,设置for
循环来迭代每个元素:
1const myCustomFilterFunction = function(callback) {
2 console.log('My Custom Filter Function!');
3
4 const newArray = [];
5
6 for (let i = 0; i < this.length; i++) {
7 console.log(this[i]);
8 }
9}
在for
循环中,你需要决定是否将每个元素添加到新数组中,这是回调函数的目的,所以你可以使用它来条件地添加每个元素,如果返回值是true
,请将元素推到返回数组:
1const myCustomFilterFunction = function(callback) {
2 console.log('My Custom Filter Function!');
3
4 const newArray = [];
5
6 for (let i = 0; i < this.length; i++) {
7 if (callback(this[i])) {
8 newArray.push(this[i]);
9 }
10 }
11
12 return newArray;
13}
让我们看看你的重写函数在行动中,通过测试它与一个函数,将显示大于1
的值:
1// arr = [1, 2, 3]
2// expected = [2, 3]
3
4console.log(arr.filterFromScratch((element) => element > 1));
您将获得以下输出:
1[secondary_label Output]
2My Custom Filter Function!
3[2, 3]
有了它,您已经实现了自定义的过滤器
函数,接下来您将使用类型
函数。
步骤3 - 执行类型
分类
函数返回从原始数组中分类的数组。
让我们创建一个新的函数,并将其分配到 Array.prototype.sortFromScratch
:
1const myCustomSortFunction = function(callback) {
2 console.log('My Custom Sort Function!');
3}
4Array.prototype.sortFromScratch = myCustomSortFunction;
5
6const arr = [3, 2, 1];
7
8arr.sortFromScratch();
我们将使用 Bubble Sort为此类型的实现. 以下是我们将采取的方法:
- 重复重复通过数组中的项目
- 比较邻近的项目,如果它们不按顺序进行交换
- 经过数组重复足够的时间来进行每个比较后,数组进行排序
使用 Bubble Sort,您必须在数组中的每个元素中完全迭代一次,这需要一个嵌入的for
循环,其中内部循环通过停止最后元素的一个短路进行迭代,所以让我们现在添加它。
<$>[注] 注:这是用于教育目的,并且不是一个高效的排序方法。
1const myCustomSortFunction = function(callback) {
2 console.log('My Custom Sort Function!');
3
4 const newArray = [];
5
6 for (let i = 0; i < newArray.length; i++) {
7 for (let j = 0; j < newArray.length - 1; j++) {
8 }
9 }
10}
要避免这种情况,您可以使用 Spread Operator将原始数组复制到新数组。
1const myCustomSortFunction = function(callback) {
2 console.log('My Custom Sort Function!');
3
4 const newArray = [...this];
5
6 for (let i = 0; i < newArray.length; i++) {
7 for (let j = 0; j < newArray.length - 1; j++) {
8 }
9 }
10}
回调函数采取两个参数,当前元素和下一个元素,并将返回它们是否顺序. 在我们的情况下,如果回调函数返回一个大于0
的数字,我们想要交换两个元素。
1const myCustomSortFunction = function(callback) {
2 console.log('My Custom Sort Function!');
3
4 const newArray = [...this];
5
6 for (let i = 0; i < newArray.length; i++) {
7 for (let j = 0; j < newArray.length - 1; j++) {
8 if (callback(newArray[j], newArray[j + 1]) > 0) {
9 // swap the elements
10 }
11 }
12 }
13}
要交换元素,您可以创建一个副本,更换第一个副本,然后用副本替换第二个副本。
1const myCustomSortFunction = function(callback) {
2 console.log('My Custom Sort Function!');
3
4 const newArray = [...this];
5
6 for (let i = 0; i < newArray.length; i++){
7 for (let j = 0; j < newArray.length - 1; j++) {
8 if (callback(newArray[j], newArray[j + 1]) > 0) {
9 const temp = newArray[j + 1];
10 newArray[j + 1] = newArray[j];
11 newArray[j] = temp;
12 }
13 }
14 }
15
16 // array is sorted
17 return newArray;
18}
让我们看看你的重写函数在行动中,通过测试它用一个从低到高分类的函数:
1// arr = [3, 2, 1]
2// expected = [1, 2, 3]
3
4console.log(arr.sortFromScratch((current, next) => current - next));
您将获得以下输出:
1[secondary_label Output]
2My Custom Sort Function!
3[1, 2, 3]
现在你已经创建了一个自定义的分类
函数,你已经准备好继续实施一个减少
函数。
步骤4 - 实施减少
减少
函数通过每个元素重复并返回一个单个值。
「減少」並不像其他函數一樣返回一個新的數列. 它實際上「減少」數列中的元素到一個最終值:一個數字、一個字符串或一個對象。
让我们创建一个新的函数,并将其分配到Array.prototype.reduceFromScratch:
1const myCustomReduceFunction = function(callback) {
2 console.log('My Custom Reduce Function!');
3}
4Array.prototype.reduceFromScratch = myCustomReduceFunction;
5
6const arr = [1, 2, 3];
7
8arr.reduceFromScratch();
要减少
返回一个最终值,它需要一个起始值来工作。用户通过的回调函数将决定如何根据数组的每个元素更新此 accumulator 并在末尾返回它。
现在添加您的for
循环,并拨打回调函数. 返回值成为新积累器. 循环结束后,您返回积累器。
1const myCustomReduceFunction = function(callback, accumulator) {
2 console.log('My Custom Reduce Function!');
3 for (let i = 0; i < this.length; i++) {
4 accumulator = callback(accumulator, this[i]);
5 }
6 return accumulator;
7}
让我们看看你的重写函数在行动中,通过测试它与一个函数,总结一个数组的内容:
1// arr = [1, 2, 3]
2// expected = 6
3
4console.log(arr.reduceFromScratch((accumulator, element) => accumulator + element, 0));
1[secondary_label Output]
2My Custom Reduce Function!
36
结论
JavaScript 的数组功能非常有用. 在本教程中,您重新实现了数组功能,以便更好地了解它们的工作方式,以便您可以更有效地使用它们。