目录
介绍
ES6发布后,我发现许多开发人员仍然不知道Array对象添加的函数。因此,我决定、创建这篇文章以传播信息,许多人将从中受益。
背景
本文不是关于JavaScript数组的介绍,而是更多有关检查JavaScript Array对象中新添加的函数的内容。如果您是初学者,建议您进行Google搜索。而且,在我看来,这些增加的函数有一个目标,那就是使我们的生活在使用数组时更加轻松并提高生产力。最后,如果您对数组有很好的了解,则可以轻松阅读本文。
ECMAScript 6增强型Arrays
如前所述,ECMAScript 6(ES6)已向全局Array对象添加了新方法。因此,我们将讨论以下方法:
- Array.from()
- Array.of()
- copyWithin()
- fill()
- find()
- findIndex()
- entries()
- keys()
- values()
因此,让我们开始吧。我希望你很兴奋。
Array.from()方法
这是一种从可迭代对象返回新Array实例的static方法。但是,您也可以在第一个参数中传递“类似数组的对象”。如果您还没有听说过,将在本节中进行讨论。
语法
//syntax
//Array.from(arrayLike[, mapFn[, thisArg]]);
参数
- arrayLike ——是可迭代对象的引用。
- mapFn ——是可选的,并充当称为map-function的回调。
- thisArg——也是可选的,并且是map-function内部的this值。
例
let result =
Array.from('JavaScript', (val, indx) => `[${indx}]` + "=>" + val.toUpperCase());
console.log(result);
输出量
如您所见,上面的示例很简单(易于理解)。
Map Function
- 第二个参数(mapFn)(如果提供)是映射回调。调用时,它将每个值从源转换为返回的目标。
- 这类似于Array.prototype.map()方法。
现在,为什么不看另一个例子,您不觉得吗?而且,为什么不把Array.from()放在Object里面呢。为了让我们来看看如何映射回调函数和第三个参数this的行为。
const manager = {
isBadManager: true,
doBadStuff: function (items) {
return Array.from(items, function (val, indx) {
if (this.isBadManager) {
console.log(`${indx + 1}. ${val[0].toUpperCase()}${val.substr(1)}`);
}
}, this);
}
}
/**
* Output:
* 1. That's my idea
* 2. Micromanage
*/
manager.doBadStuff(['that\'s my idea','micromanage']);
同样,这是一个简单易懂的示例。现在,让我们提高一个档次。并且,让我们更多地关注Array.map()的第一个参数,它是类似数组的对象(arrayLike)。
什么是类似数组的对象?
通常,您会在JavaScript中遇到一些看起来像数组的对象,通常称为“类似数组的对象”。困惑?不必如此。它是长度属性为非负整数的Object,并且具有一些索引属性。
让我们看下面的例子:
let arrLike1 = {
length: 3,
0: "Jin",
1: "Vincent",
2: "Necesario"
};
就是这样?是的! 现在,让我们看一下如何使用Array.from()将arrLike1变量转换为真实的Array。
let resultArray2 = Array.from(arrLike1);
console.log(resultArray2);
//output: ["Jin", "Vincent", "Necesario"]
NodeList
NodeList是类数组对象的另一个示例。甚至我也纠结于NodeList。我以为是数组,但不是。
NodeList和Arrays 完全不同的东西。
好,那是NodeList什么?NodeList对象是使用浏览器API (如querySelector()和/或querySelectorAll())时从HTML文档中提取的DOM节点的集合。
现在,我们有一个想法,NodeList是什么,让我们尝试使用Array.from()将NodeList转换到Array。
<!-- this is the html file -->
<body>
<div>
<p>Hello World 1</p>
<p>Hello World 2</p>
<p>Hello World 3</p>
</div>
</body>
/**
* Start of NodeList
* In this code sample we will see what a NodeList is.
* Here are some facts about NodeList.
*
* 1. NodeList aren't arrays.
* 2. NodeList does have a length property
* 3. NodeList does have indexed property
* 4. Therefore, we can conclude that a NodeList does look like
* an Array-like object.
* 5. We can convert NodeList into an array with the use of Array.from()
*/
window.addEventListener("DOMContentLoaded", function (event) {
let elements = document.querySelectorAll("div p");
console.log(elements); //output: NodeList(3) [p, p, p]
//this proves that NodeList does have a length property
console.log(elements.length) //output: 3
console.log(typeof (elements)); //output: object
//this proves that the return of querySelectorAll method is a NodeList
console.log(elements instanceof NodeList); //output: true
//this proves that NodeList aren't arrays
console.log(elements instanceof Array); //output: false
let arrayParagraphs = Array.from(elements);
console.log(arrayParagraphs); //output: Array(3)
});
/**
* End of NodeList
*/
输出
既然我们熟悉了类似数组的对象,并且已经了解了如何将其转换为真实的数组。我们需要了解的下一个概念是如何避免空插槽(slot)。
避免空插槽(slot)
空插槽(slot)?这些是什么?基本上,当您创建一定长度的Array而不指定每个索引的值时,您将拥有一个空索引,也称为一个空插槽(slot)。
让我们看下面的例子:
const arrWithEmptySlots = [];
arrWithEmptySlots.length = 5;
arrWithEmptySlots[0] = "Jin";
//output ["Jin", empty × 4]
console.log(arrWithEmptySlots);
输出:
如何检查空插槽(slot)?
我们可以使用in运算符来检查数组是否具有键。此外,它返回一个boolean值,false为空时slot,但true用于有值的slot,包括undefined值。
让我们看下面的例子:
const arrWithEmptySlots = [];
arrWithEmptySlots.length = 3;
arrWithEmptySlots[0] = undefined;
arrWithEmptySlots[1] = "Jin";
console.log(0 in arrWithEmptySlots);//true
console.log(1 in arrWithEmptySlots);//true
console.log(2 in arrWithEmptySlots);//false
console.log(3 in arrWithEmptySlots);//false
/**
* output:
* 0
* 1
*/
for (let slot in arrWithEmptySlots) {
console.log(slot);
}
这个空插槽与Array.from()方法有什么关系?
如果您想生成一个初始化为一定长度而没有空插槽的初始化Array,则Array.from()可以解决该问题。
让我们看下面的例子:
const arrayWithEmptySlots_2 = [];
arrayWithEmptySlots_2.length = 5;
const results = Array.from(arrayWithEmptySlots_2);
//output: [undefined, undefined, undefined, undefined, undefined]
console.log(results);
在我们进入下一部分之前。
我们可以得出结论,Array.from()不仅从可迭代对象创建新Array实例。它还接受一个“类似数组的对象”,该对象将被转换为Array实数,并帮助我们(JavaScript程序员)避免出现空槽。
Array.of()方法
通常,每个人都知道Array构造函数是用来创建Array对象的。此外,Array.of()方法是Array构造方法的替代方法,本节将介绍原因。
语法
//syntax
//Array.of([]);
参数
- [] ——用于创建数组的元素
让我们看下面的一些例子:
- 创建一个新的Array构造函数并传递多个参数。
let cars = new Array("Toyota", "Mitsubishi", "Nissan", "Honda");
//output: 4
console.log(cars.length);
//output: Toyota Mitsubishi Nissan Honda
console.log(...cars);
let customers = new Array({ name: "Jin" }, { name: "Vincent" }, { name: "Necesario" });
//output: 3
console.log(customers.length);
//output: {name: "Jin"} {name: "Vincent"} {name: "Necesario"}
console.log(...customers);
let luckyNumbers = new Array(23, 29, 32);
//output: 3
console.log(luckyNumbers.length);
//output: 23 29 32
console.log(...luckyNumbers);
到现在为止还挺好。让我们转到下一个示例。
- 创建一个新的Array构造函数并传递一个参数。并且,让我们看到故障。
let car = new Array("Toyota");
//still works.
console.log(car);
let customer = new Array({name: "Jin"})
//still works.
console.log(customer);
let luckyNumber = new Array(23);
//glitch
//output: 23
//23 in length????
console.log(luckyNumber.length);
//another glitch
//output: [empty × 23]
console.log(luckyNumber);
小故障?
你发现差异了吗?让我们以luckyNumber变量为例,与变量car和customer比较,结果不同。请记住,当您传递一个带有数字值的参数时。它正在创建一个空数组,其length属性等于该数字,并根据length属性产生空插槽。这是小故障吗?也许是。为了避免出现此问题,我们可以使用Array.of()方法。
让我们看下面的例子:
let superLuckyNumber = Array.of(23);
console.log(superLuckyNumber); //output: [23]
因此,Array.of()引入了解决该问题的方法。
copyWithin()方法
copyWithin()方法用于将数组的值序列复制到数组中的其他位置。
语法
//syntax
//[].copyWithin(target, start, end);
参数
- target ——将元素复制到的索引
- start ——可选,这是从其开始复制的索引位置
- end ——可选,这是实际结束复制元素的索引
如果起始索引为负,则将其视为数组长度加上起始索引([].length + start)。其结束索引([].length + end)相同。
让我们看下面的例子:
let presidents1 = ["Donald Trump", "Barack Obama", "George Bush", "Bill Clinton"];
let presidents2 = ["George H. W. Bush", "Ronald Reagan", "Jimmy Carter", "General Ford"];
//let's copy to index 0 from index 1
//let's replace Donald Trump with Barack Obama
//output: ["Barack Obama", "George Bush", "Bill Clinton", "Bill Clinton"]
console.log(presidents1.copyWithin(0, 1));
//let's copy to index 1 from index 2
//, let's replace Ronald Reagan with Jimmy Carter up to 3rd index.
//Up to 2nd index only excluding 3rd index.
//output: ["George H. W. Bush", "Jimmy Carter", "Jimmy Carter", "General Ford"]
console.log(presidents2.copyWithin(1, 2, 3));
简单明了(易于遵循)不是吗?让我们进入下一部分。
fill()方法
fill方法实际上使用给定value填充(全部或部分)从start索引到end索引的Array的所有元素。此外,start和end索引是可选的;因此,如果未提供它们,则整个Array字段将由您传递的值填充。
语法
//syntax
//[].fill(value, start, end);
参数
- value ——填充数组的值
- start ——可选,是开始索引
- end ——可选,是结束索引
如果您已经看到Array构造函数的问题。同样,我们可以使用此方法为数组的所有空插槽设置值。只要目标是初始化具有定义的长度且没有空插槽的数组,就可以执行此操作。
让我们看下面的例子:
let arryLenOf5 = new Array(5).fill(undefined);
//output: (5)[undefined, undefined, undefined, undefined, undefined]
console.log(arryLenOf5);
let arryLenOf3 = new Array(3).fill(0);
//output: (3) [0, 0, 0]
console.log(arryLenOf3);
让我们再次看一些例子:
//fills the entire array
console.log([29, 23, 5, 26, 16, 21].fill(29));
//output: [29, 29, 29, 29, 29, 29]
//fills the entire array starting at index 1
console.log([29, 23, 5, 26, 16, 21].fill(30, 1));
//output: [29, 30, 30, 30, 30, 30]
//fills the entire array starting at index 1 and ends at 5th position.
console.log([29, 23, 5, 26, 16, 21].fill(31, 2, 5));
//output: [29, 23, 31, 31, 31, 21]
如果起始索引为负,则将其视为数组长度加上起始索引([].length + start)。其与结束索引([].length + end)相同。
//fills the entire array starting at index ([].length -2) = 4th index.
console.log([29, 23, 5, 26, 16, 21].fill(31, -2));
//output: [29, 23, 5, 26, 31, 31]
//fills the entire array starting at [1] index ends to ([].length -2) = 4th position.
console.log([29, 23, 5, 26, 16, 21].fill(31, 1, -2));
//output: [29, 31, 31, 31, 16, 21]
简单明了(易于遵循)不是吗?让我们进入下一部分。
find()方法
在深入研究该find()方法之前,我们将先退一步。并回答:“它真正解决了什么?”
语法
//syntax
//[].find(callback(element,index,array), thisArg);
参数
- callback ——对数组中的每个值执行的回调函数
- thisArg——是可选的,Object用作回调内部的this
indexOf方法
通常,在Array中搜索值时首先想到的是indexOf()方法的使用。
让我们看下面的例子:
let nums = [9, 8, 7, 6, 5, 4, 3, 2, 1];
console.log(nums.indexOf(9)); //output: 0;
console.log((nums.indexOf(7) !== -1)); //output: true
console.log((nums.indexOf("9") == 0)); //output: false
console.log((nums.indexOf("Jin Vincent Necesario") !== -1)); //output: false
但是,有时程序员会忘记此方法需要严格的比较。我认为,这就是他们(程序员)使用该some()方法的原因。
some()方法
此方法通过为每个元素调用一个函数回调来起作用,直到一个返回true 或truthy值,最后停止。
好处是您可以控制值的比较,与indexOf()方法不同。
让我们看下面的例子:
let nums = [9, 8, 7, 6, 5, 4, 3, 2, 1];
console.log(nums.some((num) => num == "9")); //output: true
console.log(nums.some((num) => num === "9")); //output: false
现在,关于其some()方法的缺点是,你只能得到boolean值true或者false,如果找到了适当匹配的值,而不是实际匹配的值。
find()方法可以解决什么?
find()方法解决了该问题。它的工作原理与some()方法相同,不同之处在于一旦回调返回其值,则返回Array实际值。因此,find()方法返回一个Array元素。仅当满足所提供的条件时,该表达式才会传递给回调函数。否则,返回undefined。
让我们看下面的例子:
let nums = [9, 8, 7, 6, 5, 4, 3, 2, 1];
console.log(nums.find((num) => num == "9")); //output: 9
console.log(nums.find((num) => num === "9"));//output: undefined
为什么没有另一个带有完整参数的示例?
let num = 5;
let nums = [9, 8, 7, 6, 5, 4, 3, 2, 1];
let result = nums.find(function (value, index, array) {
//just shows the values to the console window.
console.log(`The num[${index}] is equal to ${value} ${this}`);
return value === parseInt(this);
}, num);
console.log(result); //output: 5
findIndex()方法
这几乎与find()方法相似。但是,它返回数组元素的索引,而不是元素本身。
语法
//syntax
//[].findIndex(callback(element,index,array), thisArg);
参数
- callback——一个回调函数,对数组中定每个值执行,直到函数返回true为止。否则为undefined,表示未找到该元素。
- thisArg ——是可选的
回到indexOf()方法,我们已经看到无法控制其匹配逻辑。这样,findIndex()挽救了局面。
让我们看下面的例子:
let num = 5;
let nums = [9, 8, 7, 6, 5, 4, 3, 2, 1];
let result = nums.findIndex(function (value, index, array) {
//just shows the values to the console window.
console.log(`The num[${index}] is equal to ${value} ${this}`);
return value === parseInt(this);
}, num);
console.log(result); //output: 4
似乎是一个简单的例子。而且,因为我们对find()方法有很好的了解,并且显示了它们的相似性。让我们举另一个例子,其中搜索看起来像是自定义搜索。
const houses = [
{ length: 22, width: 288, measurement: 'ft' },
{ length: 182, width: 532, measurement: 'ft' },
{ length: 12, width: 152, measurement: 'ft' },
{ length: 20, width: 30, measurement: 'ft' },
{ length: 12, width: 152, measurement: 'ft' }];
let indexResult = houses.findIndex((house) => (house.length * house.width) === 600);
console.log(indexResult); //output: 3
什么时候使用find()和findIndex()方法?
- 不要像对待findIndex()方法那样对待indexOf()方法,因为我们有some()方法可以返回所需的布尔值。
- 不要使用findIndex()方法获取匹配的值,因为这就是find()方法的目的。
- 如果需要严格匹配,请使用indexOf()方法。
- 如果需要更自定义的匹配项的索引,请使用findIndex()。
entry()方法
此方法返回一个可迭代的对象。此外,实际返回的对象是 Array Iterator
,其中包含数组每个索引的键/值对。
语法
//syntax
//[].entries();
让我们在下面看一个例子。
let fruits = ['mango', 'apple', 'dragon fruit'];
//output: returns Array Iterator {}
console.log(fruits.entries());
/*
Let us show the [key, value] pair
*/
let fruitEntries = fruits.entries();
/*
Output:
[0, "mango"]
[1, "apple"]
[2, "dragon fruit"]
*/
for (let current of fruitEntries){
console.log(current);
}
/*let us show the index and element of the fruits array
Output:
0 "mango"
1 "apple"
2 "dragon fruit"
*/
for(let [index, element] of fruits.entries()){
console.log(index, element);
}
keys()方法
该方法类似于entries()
方法。但是,返回的对象包含数组中每个索引的键。
语法
//syntax
//[].keys();
让我们在下面看一个例子。
let fruits = ['mango', 'apple', 'dragon fruit'];
//output: Array Iterator {}
console.log(fruits.keys());
let fruitKeys = fruits.keys();
//output: 0 1 2
console.log(...fruitKeys);
values()方法
此方法的行为类似于[].keys()
和[].entries()
。但是,不同的是,此方法返回数组中每个键的值。
语法
//syntax
[].values();
让我们在下面看一个例子。
let fruits = ['mango', 'apple', 'dragon fruit'];
//output: Array Iterator {}
console.log(fruits.values());
let fruitKeys = fruits.values();
//output: "mango" "apple" "dragon fruit"
console.log(...fruitKeys);
总结
在本文中,我们学习了JavaScript(ES6)语言的新Array方法。此外,我们已经解决了这些方法的工作原理,为什么要添加呢?它解决了什么问题/问题?总的来说,我们已经看到了这些方法的历史和好处