JavaScript中的数组与对象结构化 - 有什么区别?

307 阅读14分钟

JavaScript中的析构赋值为从数组和对象中提取数值提供了一种整洁而简洁的方法。

这篇文章旨在向你展示数组和对象的析构赋值在JavaScript中是如何工作的。

所以,不用多说,让我们开始学习数组析构。

什么是数组析构?

数组析构 是一种独特的技术,它允许你将一个数组的值整齐地提取到新的变量中。

例如,如果不使用数组析构赋值技术,你会像这样把一个数组的值复制到一个新的变量中:

const profile = ["Oluwatobi", "Sofela", "codesweetly.com"];

const firstName = profile[0];
const lastName = profile[1];
const website = profile[2];

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

注意,上面的片段有很多重复的代码,这不是一种DRY**(Don**'tRepeat Yourself)的编码方式。

现在让我们看看数组去结构化是如何使事情变得更整洁和干燥的:

const profile = ["Oluwatobi", "Sofela", "codesweetly.com"];

const [firstName, lastName, website] = profile;

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

你看,就像变魔术一样,我们把三个新的变量(即firstName,lastName, 和website )放到一个数组对象([...] )中,从而清理了我们的代码。然后,我们给它们分配了profile 数组的值。

换句话说,我们指示计算机将profile 数组的值提取到赋值运算符左侧的变量中。

因此,JavaScript将解析profile 数组并将其第一个值("Oluwatobi")复制到解构数组的第一个变量(firstName)。

同样地,计算机将提取profile 数组的第二个值("Sofela")到解构数组的第二个变量(lastName)。

最后,JavaScript将把profile 数组的第三个值("codesweetly.com")复制到析构数组的第三个变量(website)。

请注意,上面的片段是通过引用profile 数组来解构的。然而,你也可以直接对数组进行解构。让我们来看看怎么做。

如何直接对数组进行解构

JavaScript让你直接对数组进行解构,就像这样:

const [firstName, lastName, website] = [
  "Oluwatobi", 
  "Sofela", 
  "codesweetly.com"
];

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

假设你喜欢把你的变量声明和它们的赋值分开。在这种情况下,JavaScript可以帮你解决这个问题。让我们来看看如何。

如何使用数组析构,同时将变量声明与它们的赋值分开?

每当你使用数组析构时,JavaScript允许你将变量声明和它们的赋值分开。

这里有一个例子

let firstName, lastName, website;

[firstName, lastName, website] = ["Oluwatobi", "Sofela", "codesweetly.com"];

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

如果你想把"Oluwatobi" 赋值给firstName 变量,而把其余的数组项赋值给另一个变量,该怎么办?你是如何做到的?让我们在下面找出答案。

如何使用Array Destructuring将数组字头的其余部分分配给一个变量?

JavaScript允许你在一个去结构化数组中使用rest操作符,将一个普通数组的其余部分分配给一个变量。

这里有一个例子

const [firstName, ...otherInfo] = ["Oluwatobi", "Sofela", "codesweetly.com"];

console.log(firstName); // "Oluwatobi"
console.log(otherInfo); // ["Sofela", "codesweetly.com"]

注意 一定要把rest操作符作为你的析构数组的最后一项,以避免得到SyntaxError

现在,如果你只想提取"codesweetly.com" 呢?让我们在下面讨论一下你可以使用的技术。

如何使用数组去结构化来提取任何索引上的值

下面是你如何使用数组析构来提取普通数组中任何索引位置的值:

const [, , website] = ["Oluwatobi", "Sofela", "codesweetly.com"];

console.log(website); // "codesweetly.com"

在上面的片段中,我们使用逗号来跳过位于解构数组第一个和第二个索引位置的变量。

通过这样做,我们能够将website 变量与赋值运算符右侧的正规数组的第三个索引值联系起来(即"codesweetly.com" )。

但有时,你希望从数组中提取的值是undefined 。在这种情况下,JavaScript提供了一种在析构数组中设置默认值的方法。下面我们就来了解一下。

默认值在数组析构赋值中如何工作

当你想从数组中提取的值不存在(或被设置为undefined )时,设置一个默认值会很方便。

下面是你如何在一个解构数组中设置一个默认值:

const [firstName = "Tobi", website = "CodeSweetly"] = ["Oluwatobi"];

console.log(firstName); // "Oluwatobi"
console.log(website); // "CodeSweetly"

在上面的片段中,我们将"Tobi""CodeSweetly" 设置为firstNamewebsite 变量的默认值。

因此,在我们试图从右侧数组中提取第一个索引值时,计算机默认为"CodeSweetly"- 因为在["Oluwatobi"] 中只存在一个第2个索引值。

那么,如果你需要将firstName的值与website 的值交换呢?同样,你可以使用数组的解构来完成这个工作。让我们来看看如何。

如何使用数组析构来交换变量的值

你可以使用数组析构赋值来交换两个或多个不同变量的值。

这里有一个例子

let firstName = "Oluwatobi";
let website = "CodeSweetly";

[firstName, website] = [website, firstName];

console.log(firstName); // "CodeSweetly"
console.log(website); // "Oluwatobi"

在上面的片段中,我们使用直接的数组析构来重新分配firstNamewebsite 变量与赋值运算符右边的数组字面的值。

因此,firstName的值将从"Oluwatobi" 改为"CodeSweetly" 。而website的内容将从"CodeSweetly" 改为"Oluwatobi"

请记住,你也可以使用数组析构来从一个普通的数组中提取值到一个函数的参数。让我们在下面进一步讨论这个问题。

如何使用数组析构从数组中提取值到函数的参数上

下面是你如何使用数组析构来提取数组的值到一个函数的参数:

// Define an array with two items:
const profile = ["Oluwatobi", "Sofela"];

// Define a function with one destructuring array containing two parameters:
function getUserBio([firstName, lastName]) {
  return `My name is ${firstName} ${lastName}.`;
}

// Invoke getUserBio while passing the profile array as an argument:
getUserBio(profile);

// The invocation above will return:
"My name is Oluwatobi Sofela."

在上面的片段中,我们使用数组析构参数将profile 数组的值提取到getUserBio'sfirstNamelastName 参数中。

注意: 一个数组析构参数通常被称为析构参数

下面是另一个例子

// Define an array with two string values and one nested array:
const profile = ["codesweetly.com", "Male", ["Oluwatobi", "Sofela"]];

// Define a function with two destructuring arrays containing a parameter each:
function getUserBio([website, , [userName]]) {
  return `${userName} runs ${website}`;
}

// Invoke getUserBio while passing the profile array as an argument:
getUserBio(profile);

// The invocation above will return:
"Oluwatobi runs codesweetly.com"

在上面的片段中,我们使用了两个数组析构参数来提取profile 数组的值到getUserBio'swebsiteuserName 参数中。

有些时候,你可能需要调用一个包含析构参数的函数,而不向它传递任何参数。在这种情况下,你需要使用一种技术来防止浏览器抛出一个TypeError

让我们来了解一下下面的技术。

如何在不提供任何参数的情况下调用一个包含数组析构参数的函数

考虑一下下面的函数:

function getUserBio([firstName]) {
  console.log(
    "Do something else that does not need the destructuring parameter."
  );
  return `My name is ${firstName}.`;
}

现在,让我们在不向其析构参数传递任何参数的情况下调用getUserBio 函数:

getUserBio();

在调用上面的getUserBio 函数后,浏览器会抛出一个类似于TypeError: undefined is not iterable 的错误。

TypeError 信息的发生是因为含有析构参数的函数希望你至少提供一个参数。

所以,你可以通过给析构参数指定一个默认参数来避免此类错误信息。

这里有一个例子

function getUserBio([firstName] = []) {
  console.log(
    "Do something else that does not need the destructuring parameter."
  );
  return `My name is ${firstName}.`;
}

注意在上面的片段中,我们分配了一个空数组作为析构参数的默认参数。

所以,现在让我们调用getUserBio 函数,不给它的析构参数传递任何参数:

getUserBio();

该函数将输出:

"Do something else that does not need the destructuring parameter."
"My name is undefined."

请记住,你不必使用一个空数组作为析构参数的默认参数。你可以使用任何其他非nullundefined 的值。

所以,现在我们知道了数组析构是如何工作的,让我们来讨论一下对象析构,这样我们就可以看到其中的区别。

什么是JavaScript中的对象析构?

对象析构 是一种独特的技术,它允许你将一个对象的值整齐地提取到新的变量中。

例如,如果不使用对象重构赋值技术,我们会像这样把一个对象的值提取到一个新的变量中:

const profile = {
  firstName: "Oluwatobi", 
  lastName: "Sofela", 
  website: "codesweetly.com"
};

const firstName = profile.firstName;
const lastName = profile.lastName;
const website = profile.website;

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

注意,上面的片段有很多重复的代码,这不是一种DRY**(Don**'tRepeat Yourself)的编码方式。

现在让我们来看看对象的结构化赋值是如何使事情变得更整洁和简洁的:

const profile = {
  firstName: "Oluwatobi", 
  lastName: "Sofela", 
  website: "codesweetly.com"
};

const { firstName: firstName, lastName: lastName, website: website } = profile;

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

你看,就像变魔术一样,我们通过将三个新的变量放入一个属性对象({...}),并将profile 对象的值分配给它们,从而清理了我们的代码。

换句话说,我们指示计算机将profile 对象的值提取到赋值运算符左侧的变量中。

因此,JavaScript将解析profile 对象并将其第一个值("Oluwatobi")复制到解构对象的第一个变量(firstName)。

同样地,计算机将提取profile 对象的第二个值("Sofela")到结构化对象的第二个变量(lastName)。

最后,JavaScript将把profile 对象的第三个值("codesweetly.com")复制到析构对象的第三个变量(website)。

请记住,在{ firstName: firstName, lastName: lastName, website: website } ,键是对profile 对象的属性的引用--而键的值代表新的变量。

Anatomy of a JavaScript object destructuring assignment

JavaScript对象解构赋值的结构图

另外,你也可以使用速记语法来使你的代码更容易阅读。

这里有一个例子

const profile = {
  firstName: "Oluwatobi", 
  lastName: "Sofela", 
  website: "codesweetly.com"
};

const { firstName, lastName, website } = profile;

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

在上面的片段中,我们把{ firstName: firstName, age: age, gender: gender } 简称为{ firstName, age, gender } 。你可以在这里了解更多关于速记技术的信息。

请注意,上面的片段说明了当对象的属性和变量都有相同的名字时,如何将对象的值赋给一个变量。

然而,你也可以将一个属性的值赋给一个不同名称的变量。让我们来看看如何。

当属性的名称与变量的名称不同时,如何使用对象析构?

JavaScript允许你使用对象析构将一个属性的值提取到一个变量中,即使该属性和变量的名字都不一样。

这里有一个例子

const profile = {
  firstName: "Oluwatobi", 
  lastName: "Sofela", 
  website: "codesweetly.com"
};

const { firstName: forename, lastName: surname, website: onlineSite } = profile;

console.log(forename); // "Oluwatobi"
console.log(surname); // "Sofela"
console.log(onlineSite); // "codesweetly.com"
console.log(website); // "ReferenceError: website is not defined"

在上面的片段中,计算机成功地将profile 对象的值提取到名为forename,surname, 和onlineSite的变量中--尽管属性和变量的名称不同。

注意: const { firstName: forename } = profile 等同于const forename = profile.firstName

下面是另一个例子

const profile = {
  lastName: { familyName: "Sofela" }
};

const { lastName: { familyName: surname } } = profile;

console.log(surname); // "Sofela"

在上面的片段中,计算机成功地将profile 对象的值提取到surname 变量中--尽管属性和变量的名称不同。

注意: const { lastName: { familyName: surname } } = profile 相当于const surname = profile.lastName.familyName

请注意,到目前为止,我们是通过引用profile 对象来解构它的。然而,你也可以直接对一个对象进行解构。让我们来看看如何做。

如何进行直接的对象重组

JavaScript允许直接对一个属性对象进行重组,就像这样:

const { firstName, lastName, website } = {
  firstName: "Oluwatobi", 
  lastName: "Sofela", 
  website: "codesweetly.com"
};

console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

假设你喜欢把你的变量声明和它们的赋值分开。在这种情况下,JavaScript为你提供了保障。让我们看看如何。

如何使用对象析构,同时将变量声明与它们的赋值分开?

每当你使用对象析构时,JavaScript允许你将变量声明和它们的赋值分开。

这里有一个例子

// Declare three variables:
let firstName, lastName, website;

// Extract values to the three variables above:
({ firstName, lastName, website } = {
  firstName: "Oluwatobi", 
  lastName: "Sofela", 
  website: "codesweetly.com"
});

// Invoke the three variables:
console.log(firstName); // "Oluwatobi"
console.log(lastName); // "Sofela"
console.log(website); // "codesweetly.com"

注意

  • 确保你把对象结构化的赋值用圆括号括起来。这样做,计算机就会知道,对象析构是一个对象字面,而不是一个块。
  • 在对象结构化赋值的小括号后面放一个分号(;)。通过这样做,你将防止计算机将括号解释为可能在前一行的函数的调用者。

如果你想把"Oluwatobi" 赋值给firstName 变量,而把对象的其他值赋值给另一个变量,该怎么办?你怎样才能做到这一点呢?让我们在下面找出答案。

如何使用对象去结构化将对象的其余部分分配给一个变量

JavaScript允许你在一个析构对象中使用rest操作符,将一个对象字面的其余部分分配给一个变量。

这里有一个例子

const { firstName, ...otherInfo } = {
  firstName: "Oluwatobi",
  lastName: "Sofela",
  website: "codesweetly.com"
};

console.log(firstName); // "Oluwatobi"
console.log(otherInfo); // {lastName: "Sofela", website: "codesweetly.com"}

注意 一定要将rest操作符作为你的析构对象的最后一项,以避免得到SyntaxError

有时,你希望从属性对象中提取的值是undefined 。在这种情况下,JavaScript提供了一种方法来在析构对象中设置默认值。下面我们就来了解一下。

默认值如何在对象析构赋值中工作

当你想从一个对象中提取的值不存在(或被设置为undefined )时,设置一个缺省值会很方便。

下面是你如何在一个去结构化属性对象中设置一个默认值。

const { firstName = "Tobi", website = "CodeSweetly" } = {
  firstName: "Oluwatobi"
};

console.log(firstName); // "Oluwatobi"
console.log(website); // "CodeSweetly"

在上面的片段中,我们将"Tobi""CodeSweetly" 设置为firstNamewebsite 变量的默认值。

因此,在我们试图从右侧对象中提取第二个属性的值时,计算机默认为"CodeSweetly"- 因为{firstName: "Oluwatobi"} 中只存在一个属性。

那么,如果你需要将firstName的值与website 的值交换呢?同样,你可以使用对象重构来完成这项工作。让我们看看下面的方法。

如何使用对象析构来交换值

你可以使用对象析构赋值来交换两个或多个不同变量的值。

这里有一个例子

let firstName = "Oluwatobi";
let website = "CodeSweetly";

({ firstName, website } = {firstName: website, website: firstName});

console.log(firstName); // "CodeSweetly"
console.log(website); // "Oluwatobi"

上面的片段使用了直接的对象析构来重新分配firstNamewebsite 变量与赋值运算符右侧的对象字面的值。

因此,firstName'的值将从"Oluwatobi" 变为"CodeSweetly" 。而website'的内容将从"CodeSweetly" 变为"Oluwatobi"

请记住,你也可以使用对象析构来从属性中提取值到一个函数的参数。让我们在下面进一步讨论这个问题。

如何使用对象析构从属性中提取值到函数的参数上

下面是你如何使用对象析构来复制一个属性的值到一个函数的参数。

// Define an object with two properties:
const profile = {
  firstName: "Oluwatobi",
  lastName: "Sofela",
};

// Define a function with one destructuring object containing two parameters:
function getUserBio({ firstName, lastName }) {
  return `My name is ${firstName} ${lastName}.`;
}

// Invoke getUserBio while passing the profile object as an argument:
getUserBio(profile);

// The invocation above will return:
"My name is Oluwatobi Sofela."

在上面的片段中,我们使用对象析构参数将profile 对象的值复制到getUserBiofirstNamelastName 参数中。

注意 一个对象析构参数通常被称为析构参数

这里是另一个例子

// Define an object with three-parent properties:
const profile = {
  website: "codesweetly.com",
  gender: "Male",
  fullName: {
    firstName: "Oluwatobi",
    lastName: "Sofela"
  }
};

// Define a function with two destructuring objects containing a parameter each:
function getUserBio({ website, fullName: { firstName: userName } }) {
  return `${userName} runs ${website}`;
}

// Invoke getUserBio while passing the profile object as an argument:
getUserBio(profile);

// The invocation above will return:
"Oluwatobi runs codesweetly.com"

在上面的代码段中,我们使用两个析构参数将profile 对象的值复制到getUserBio'swebsiteuserName 参数中。

注意: 如果你对上面的析构参数不清楚,你可以通过回顾本节更好地掌握它。

有些时候,你可能需要调用一个含有析构参数的函数,而不向它传递任何参数。在这种情况下,你需要使用一种技术来防止浏览器抛出一个TypeError

让我们来了解一下下面的技术。

如何在不提供任何参数的情况下调用一个包含去结构化参数的函数

考虑一下下面的函数:

function getUserBio({ firstName }) {
  console.log(
    "Do something else that does not need the destructuring parameter."
  );
  return `My name is ${firstName}.`;
}

现在,让我们调用getUserBio ,而不给它的去结构化参数传递任何参数:

getUserBio();

调用上面的getUserBio 函数后,浏览器会抛出一个与TypeError: (destructured parameter) is undefined 类似的错误。

TypeError 消息的发生是因为含有析构参数的函数希望你至少提供一个参数。

所以,你可以通过给析构参数指定一个默认参数来避免此类错误信息。

这里有一个例子

function getUserBio({ firstName } = {}) {
  console.log(
    "Do something else that does not need the destructuring parameter."
  );
  return `My name is ${firstName}.`;
}

注意,在上面的片段中,我们分配了一个空对象作为析构参数的默认参数。

所以,现在让我们调用getUserBio 函数,不给它的析构参数传递任何参数:

getUserBio();

该函数将输出:

"Do something else that does not need the destructuring parameter."
"My name is undefined."

请记住,你不必使用一个空对象作为析构参数的默认参数。你可以使用任何其他非nullundefined 的值。

结束语

数组和对象的析构工作类似。这两种析构分配的主要区别在于此:

  • 阵列析构从一个数组中提取值。但是对象析构从一个JavaScript对象中提取数值。

概述

这篇文章讨论了数组和对象析构在JavaScript中是如何工作的。我们还看了这两种析构作业的主要区别。

谢谢你的阅读!