数组

在本模块的最后一篇文章中,我们将了解数组——一种将数据项列表存储在单个变量名下的巧妙方法。在这里,我们将探讨这样做的好处,然后探索如何创建数组、检索、添加和删除存储在数组中的项,以及更多内容。

先决条件 对 HTML 和 CSS 的基本了解,以及对 JavaScript 的理解。
目标 了解什么是数组以及如何在 JavaScript 中操作它们。

什么是数组?

数组通常被描述为“类似列表的对象”;它们基本上是包含存储在列表中的多个值的单个对象。数组对象可以存储在变量中,并且可以像任何其他类型的值一样处理,区别在于我们可以单独访问列表中的每个值,并对列表执行非常有用且高效的操作,例如循环遍历它并对每个值执行相同的操作。也许我们有一系列产品项目及其价格存储在数组中,我们希望循环遍历它们并在发票上打印出来,同时计算所有价格的总和并在底部打印出总价。

如果我们没有数组,我们将不得不将每个项目存储在单独的变量中,然后分别为每个项目调用执行打印和添加的代码。这样写起来会更长、效率更低且更容易出错。如果我们有 10 个项目要添加到发票中,这已经很烦人了,但是 100 个项目或 1000 个项目呢?我们将在本文后面回到这个示例。

与之前的文章一样,让我们通过在浏览器开发者控制台中输入一些示例来学习数组的基本知识。

创建数组

数组由方括号和用逗号分隔的项组成。

  1. 假设我们要将购物清单存储在数组中。将以下代码粘贴到控制台中
    js
    const shopping = ["bread", "milk", "cheese", "hummus", "noodles"];
    console.log(shopping);
    
  2. 在上面的示例中,每个项目都是一个字符串,但在数组中,我们可以存储各种数据类型——字符串、数字、对象,甚至其他数组。我们也可以在一个数组中混合数据类型——我们不必将自己限制在在一个数组中只存储数字,而在另一个数组中只存储字符串。例如
    js
    const sequence = [1, 1, 2, 3, 5, 8, 13];
    const random = ["tree", 795, [0, 1, 2]];
    
  3. 在继续之前,创建一些示例数组。

查找数组的长度

您可以通过与查找字符串长度(以字符为单位)完全相同的方式查找数组的长度(其中包含多少个项目)——使用length 属性。尝试以下操作

js
const shopping = ["bread", "milk", "cheese", "hummus", "noodles"];
console.log(shopping.length); // 5

访问和修改数组项

数组中的项目编号从零开始。此数字称为项目的索引。因此,第一个项目的索引为 0,第二个项目的索引为 1,依此类推。您可以使用方括号表示法和提供项目的索引来访问数组中的各个项目,就像您访问字符串中的字母一样。

  1. 将以下内容输入您的控制台
    js
    const shopping = ["bread", "milk", "cheese", "hummus", "noodles"];
    console.log(shopping[0]);
    // returns "bread"
    
  2. 您还可以通过为单个数组项赋予新值来修改数组中的项。试试这个
    js
    const shopping = ["bread", "milk", "cheese", "hummus", "noodles"];
    shopping[0] = "tahini";
    console.log(shopping);
    // shopping will now return [ "tahini", "milk", "cheese", "hummus", "noodles" ]
    

    注意:我们之前说过,但作为提醒——JavaScript 从零开始为数组编制索引!

  3. 请注意,数组内的数组称为多维数组。您可以通过将两组方括号连接在一起来访问数组内本身位于另一个数组内的项。例如,要访问random数组(请参阅上一节)中第三个项目内的数组中的其中一个项目,我们可以执行以下操作
    js
    const random = ["tree", 795, [0, 1, 2]];
    random[2][2];
    
  4. 在继续之前,尝试对您的数组示例进行更多修改。玩一玩,看看什么有效,什么无效。

查找数组中项的索引

如果您不知道项目的索引,可以使用indexOf() 方法。indexOf()方法将项目作为参数,并将返回项目的索引或-1(如果项目不在数组中)。

js
const birds = ["Parrot", "Falcon", "Owl"];
console.log(birds.indexOf("Owl")); //  2
console.log(birds.indexOf("Rabbit")); // -1

添加项

要将一个或多个项目添加到数组的末尾,我们可以使用push()。请注意,您需要包含一个或多个要添加到数组末尾的项目。

js
const cities = ["Manchester", "Liverpool"];
cities.push("Cardiff");
console.log(cities); // [ "Manchester", "Liverpool", "Cardiff" ]
cities.push("Bradford", "Brighton");
console.log(cities); // [ "Manchester", "Liverpool", "Cardiff", "Bradford", "Brighton" ]

方法调用完成后将返回数组的新长度。如果要将新数组长度存储在变量中,可以执行以下操作

js
const cities = ["Manchester", "Liverpool"];
const newLength = cities.push("Bristol");
console.log(cities); // [ "Manchester", "Liverpool", "Bristol" ]
console.log(newLength); // 3

要将项目添加到数组的开头,请使用unshift()

js
const cities = ["Manchester", "Liverpool"];
cities.unshift("Edinburgh");
console.log(cities); // [ "Edinburgh", "Manchester", "Liverpool" ]

删除项

要从数组中删除最后一个项目,请使用pop()

js
const cities = ["Manchester", "Liverpool"];
cities.pop();
console.log(cities); // [ "Manchester" ]

pop()方法返回已删除的项目。要将该项目保存在新变量中,可以执行以下操作

js
const cities = ["Manchester", "Liverpool"];
const removedCity = cities.pop();
console.log(removedCity); // "Liverpool"

要从数组中删除第一个项目,请使用shift()

js
const cities = ["Manchester", "Liverpool"];
cities.shift();
console.log(cities); // [ "Liverpool" ]

如果您知道项目的索引,则可以使用splice()将其从数组中删除

js
const cities = ["Manchester", "Liverpool", "Edinburgh", "Carlisle"];
const index = cities.indexOf("Liverpool");
if (index !== -1) {
  cities.splice(index, 1);
}
console.log(cities); // [ "Manchester", "Edinburgh", "Carlisle" ]

在此对splice()的调用中,第一个参数表示从哪里开始删除项目,第二个参数表示应删除多少个项目。因此,您可以删除多个项目

js
const cities = ["Manchester", "Liverpool", "Edinburgh", "Carlisle"];
const index = cities.indexOf("Liverpool");
if (index !== -1) {
  cities.splice(index, 2);
}
console.log(cities); // [ "Manchester", "Carlisle" ]

访问每个项

很多时候,您需要访问数组中的每个项目。您可以使用for...of语句来执行此操作

js
const birds = ["Parrot", "Falcon", "Owl"];

for (const bird of birds) {
  console.log(bird);
}

有时您希望对数组中的每个项目执行相同的操作,从而得到一个包含已更改项目的数组。您可以使用map()来执行此操作。以下代码获取一个数字数组,并将每个数字加倍

js
function double(number) {
  return number * 2;
}
const numbers = [5, 2, 7, 6];
const doubled = numbers.map(double);
console.log(doubled); // [ 10, 4, 14, 12 ]

我们将一个函数传递给map(),并且map()为数组中的每个项目调用该函数一次,并将项目作为参数传递。然后,它将每次函数调用的返回值添加到一个新数组中,最后返回该新数组。

有时您希望创建一个新数组,其中只包含原始数组中与某些测试匹配的项目。您可以使用filter()来执行此操作。以下代码获取一个字符串数组,并返回一个仅包含长度大于 8 个字符的字符串的数组

js
function isLong(city) {
  return city.length > 8;
}
const cities = ["London", "Liverpool", "Totnes", "Edinburgh"];
const longer = cities.filter(isLong);
console.log(longer); // [ "Liverpool", "Edinburgh" ]

map()一样,我们将一个函数传递给filter()方法,并且filter()为数组中的每个项目调用此函数,并将项目作为参数传递。如果函数返回true,则将该项目添加到一个新数组中。最后,它返回该新数组。

在字符串和数组之间转换

通常,您会看到一些包含在一个很长的字符串中的原始数据,并且您可能希望将有用的项目分离到更方便的形式中,然后对其进行操作,例如在数据表中显示它们。为此,我们可以使用split()方法。在其最简单的形式中,它接受一个参数,即您想要在其中分隔字符串的字符,并将分隔符之间的子字符串作为数组中的项目返回。

注意:好的,从技术上讲,这是一种字符串方法,而不是数组方法,但我们将其与数组一起放在这里,因为它很适合在这里。

  1. 让我们一起操作一下,看看它是如何工作的。首先,在您的控制台中创建一个字符串
    js
    const data = "Manchester,London,Liverpool,Birmingham,Leeds,Carlisle";
    
  2. 现在让我们在每个逗号处拆分它
    js
    const cities = data.split(",");
    cities;
    
  3. 最后,尝试查找新数组的长度并从中检索一些项目
    js
    cities.length;
    cities[0]; // the first item in the array
    cities[1]; // the second item in the array
    cities[cities.length - 1]; // the last item in the array
    
  4. 您还可以使用join()方法反过来操作。尝试以下操作
    js
    const commaSeparated = cities.join(",");
    commaSeparated;
    
  5. 将数组转换为字符串的另一种方法是使用toString()方法。toString()可以说比join()更简单,因为它不带参数,但更受限制。使用join(),您可以指定不同的分隔符,而toString()始终使用逗号。(尝试使用与逗号不同的字符运行步骤 4。)
    js
    const dogNames = ["Rocket", "Flash", "Bella", "Slugger"];
    dogNames.toString(); // Rocket,Flash,Bella,Slugger
    

主动学习:打印这些产品

让我们回到我们之前描述的示例——在发票上打印出产品名称和价格,然后计算价格总和并在底部打印出来。在下面的可编辑示例中,有一些包含数字的注释——每个注释都标记了一个必须向代码中添加内容的位置。它们如下所示

  1. // number 1注释下方,有一些字符串,每个字符串都包含用冒号分隔的产品名称和价格。我们希望您将其转换为数组并将其存储在名为products的数组中。
  2. // number 2注释下方,开始一个for...of()循环以遍历products数组中的每个项目。
  3. // number 3注释下方,我们希望您编写一行代码,将当前数组项(name:price)拆分为两个单独的项目,一个只包含名称,另一个只包含价格。如果您不确定如何执行此操作,请参阅有用的字符串方法文章以获取帮助,或者更好的是,查看本文的字符串和数组之间的转换部分。
  4. 作为上述代码的一部分,您还需要将价格从字符串转换为数字。如果您不记得如何执行此操作,请查看第一篇字符串文章
  5. 有一个名为total的变量,它在代码顶部创建并赋值为 0。在循环内(在// number 4下方),我们希望您添加一行代码,在循环的每次迭代中将当前项目价格添加到该总计中,以便在代码结束时将正确的总计打印到发票上。您可能需要一个赋值运算符来执行此操作。
  6. 我们希望您更改// number 5正下方的行,以便使itemText变量等于“当前项目名称 - $当前项目价格”,例如“鞋子 - $23.99”,以便在每种情况下在发票上打印出每个项目的正确信息。这只是一个简单的字符串连接,您应该熟悉它。
  7. 最后,在// number 6注释下方,您需要添加一个}以标记for...of()循环的结束。

主动学习:前 5 名搜索

push()pop()这样的数组方法的一个很好的用途是在维护 Web 应用程序中当前活动项目的记录时。例如,在动画场景中,您可能有一个表示当前显示的背景图形的对象数组,并且出于性能或避免混乱的原因,您可能只想一次显示 50 个。随着新对象的创建和添加到数组中,可以从数组中删除旧的对象以维持所需的数量。

在此示例中,我们将展示一个更简单的用途——在这里,我们为您提供了一个假的搜索网站,带有一个搜索框。其想法是,当在搜索框中输入术语时,前 5 个以前的搜索术语将显示在列表中。当术语数量超过 5 时,每次将新术语添加到顶部时,最后一个术语将开始被删除,因此始终显示前 5 个以前的术语。

注意:在真实的搜索应用程序中,您可能能够点击以前的搜索术语以返回到以前的搜索,并且它将显示实际的搜索结果!我们现在只是保持简单。

要完成该应用程序,我们需要您

  1. // number 1注释下方添加一行代码,将当前输入到搜索输入中的值添加到数组的开头。可以使用searchInput.value检索它。
  2. // number 2注释下方添加一行代码,删除当前位于数组末尾的值。

测试你的技能!

您已经阅读完本文,但您还记得最重要的信息吗?在继续学习之前,您可以进行一些额外的测试来验证您是否保留了这些信息——请查看测试您的技能:数组

结论

阅读完本文后,我们相信您会同意数组非常有用;您会在 JavaScript 中随处可见它们,通常与循环结合使用,以便对数组中的每个项目执行相同的操作。在下一模块中,我们将教授您关于循环的所有有用的基础知识,但现在您应该给自己鼓掌并休息一下;您已经完成了本模块的所有文章!

剩下的唯一事情就是完成本模块的评估,这将测试您对之前文章的理解。

另请参阅

  • 索引集合——关于数组及其近亲类型化数组的高级指南。
  • Array——Array 对象参考页面——详细的参考指南,涵盖了本页中讨论的功能,以及更多其他功能。