目录

📶 JavaScript 解构赋值

在 JavaScript 中最常用的两种数据结构是 对象 Object 和 数组 Array。要将它们传递给函数,函数可能不需要 整个对象或者数组。

解构赋值 是一种特殊的语法,它使我们可以将数组或对象「拆包」至一系列变量中,因为有时这样更方便。

# 数组解构

🌰 例子 / 将数组结构到变量:

let arr = ["John", "Smith"]

let [firstName, surname] = arr
// 相当于 firstName = arr[0], surname = arr[1]
1
2
3
4

在新的变量上进行的操作不会影响到原来的数组元素。

🌰 例子 / 对字符串使用解构:

let [firstName, surname] = 'John Smith'.split(' ')
1

注意

「解构」不意味着「破坏」:解构通过将结构中的各元素 复制 到变量中来达到「解构」的目的。但数组本身是没有被修改的

🌰 例子 / 使用「 ,逗号选择性赋值::

let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
// 第二个元素不需要,使用逗号跳过,并且剩下的元素没有对应变量也会被忽略
1
2

🌰 例子 / 等号的右侧可以是 任何可迭代对象

let [a, b, c] = "abc"; // ["a", "b", "c"]
let [one, two, three] = new Set([1, 2, 3]);
1
2

🌰 例子 / 等号的左侧可以是任何「可以被赋值的」:

let user = {}
[user.firstName, user.surname] = 'John Smith'.split(' ') 
1
2

🌰 例子 / 配合 .entries 循环(只循环其中特定的值):

let user = {
  name: 'Simon'.
  age: 30,
  gender: 'male'
}

for(let [key, value] of Object.entries(user)) {
  console.log(`${key}: ${name}`)
}
1
2
3
4
5
6
7
8
9

对于 Map 可迭代的对象更简单:

let user = new Map()
user.set('name', 'Simon')
user.set('age', 30)
user.set('gender', 'male')

for(let [key, value] of user) {
  console.log(`${key}: ${value}`)
}
1
2
3
4
5
6
7
8

🍎 🌰 例子 / 使用解构赋值交换变量:

let guest = "Jane";
let admin = "Pete";

[guest, admin] = [admin, guest]
1
2
3
4

创建了一个由两个变量组成的临时数组,并且立即以交换了的顺序对其进行了解构。这样解决两个及以上的变量的交换一下就简单了。

# 剩余项

当不设置相应的变量接收对应的数组项,这里剩余的数组项可以使用 加一个参数来接收。

🌰 例子:

let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];

console.log(rest) // ["Consul", "of the Roman Republic"]
1
2
3

rest 的值就是数组中剩下的元素组成的 数组

# 默认值

如果数组比等号左边的变量列表短,这里也不会出现报错。缺少的值被认为是 undefined

🌰 例子:

let [firstName, surname] = [];

console.log(firstName); // undefined
console.log(surname); // undefined
1
2
3
4

对于可能没有的值,可以设置一个默认值,避免出现 undefined

🌰 例子:

let [name = "Guest", surname = "Anonymous"] = ["Julius"];
console.log(name, surname) // "Julius", "Anonymous"
1
2

默认值可以是 更加复杂的表达式 甚至可以是 函数调用,这些表达式或函数只会在这个变量 未被赋值的时候 才会被计算。

🌰 例子 / 使用函数作为默认值:

let [name = prompt('name?'), surname = prompt('surname?')] = ["Julius"];

console.log(name, surname)
1
2
3

这样当 surname 没有提供值时,会发起输入框。

# 对象解构

基本语法:

let {var1, var2} = {var1: ..., var2: ...}
1

在等号右侧应该有 一个已经存在的对象,等号左侧包含了对象 相应属性的一个类对象「模式(pattern)」。在最简单的情况下,等号左侧的就是 {...} 中的变量名列表。

🌰 例子:

let options = {
  title: "Menu",
  width: 100,
  height: 200
};

let {title, width, height} = options;
console.log(title);  // Menu
console.log(width);  // 100
console.log(height); // 200
1
2
3
4
5
6
7
8
9
10

🌰 例子 / 等号左边的模式不需要按照对象中的顺序也可以,会自动对应上。

let {height, width, title} = { title: "Menu", height: 200, width: 100 }
1

🌰 例子 / 等号左侧的模式可以更加复杂,并且指定了属性和变量之间的映射关系。

要把一个属性赋值给另一个名字的变量,比如把 options.width 属性赋值给名为 w 的变量,那么可以使用冒号来设置变量名称:

let options = {
  title: "Menu",
  width: 100,
  height: 200
};

// { sourceProperty: targetVariable }
let {width: w, height: h, title} = options;

// width -> w
// height -> h
// title -> title

console.log(w)
console.log(h)
console.log(title)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

冒号表示 什么值:赋值给谁 。上面的例子中,属性 width 被赋值给了 w ,属性 height 被赋值给了 h ,属性 title 被赋值给了同名变量。

🌰 例子 / 对可能缺失的属性设置默认值:

let options = {
  title: "Menu"
};

let {width = 100, height = 200, title} = options;
1
2
3
4
5

🌰 例子 / 默认值可以为任意表达式或函数调用,会在未提供对应的值时才会被计算 / 调用。

let options = {
  title: "Menu"
};

let {width = prompt("width?"), title = prompt("title?")} = options;
1
2
3
4
5

🌰 例子 / 将 : 的使用与等号 = 结合:

let options = {
  title: "Menu"
};

let {width: w = 100, height: h = 200, title} = options;

console.log(w)
console.log(h)
console.log(title)
1
2
3
4
5
6
7
8
9

🌰 例子 / 只提取所需的内容

let options = {
  title: "Menu",
  width: 100,
  height: 200
};

// 仅提取 title 作为变量
let { title } = options;
1
2
3
4
5
6
7
8

# 剩余模式

使用方式与数组解构中的 ... 中类似,在对象中的 剩余模式 ,把没有提取的对象属性保存到一个对象中。

🌰 例子 :

let options = {
  title: "Menu",
  height: 200,
  width: 100
};

let {title, ...rest} = options;
console.log(rest) // { height: 200, width: 100 }
1
2
3
4
5
6
7
8

注意

() 的使用:并且要注意在 JavaScript 中 { ... } 中当做一个 代码块。这样的代码块可以用于对语句分组,就是说 { ... } 中也可以 let 声明变量并且使用。为了在对象解构时,需要 JavaScript 认为 这不是 { } 代码块而是对象 ,所以要用 ( ... ) 括号包起来(在箭头函数中返回对象时同样有用到这个原理)

let title, width, height;

({title, width, height} = {title: "Menu", width: 200, height: 100});
1
2
3

# 嵌套解构

如果一个对象或数组嵌套了其他的对象和数组,可以在等号左侧使用 更复杂的模式(pattern)提取更深层的数据

🌰 例子 / 赋值语句中等号左侧的模式(pattern)具有相同的结构以从中提取值:

let options = {
  size: {
    width: 100,
    height: 200
  },
  items: ["Cake", "Donut"],
  extra: true
};

let {
  size: { // 把 size 赋值到这里
    width,
    height
  },
  items: [item1, item2], // 把 items 赋值到这里
  title = "Menu" // 在对象中不存在(使用默认值)
} = options;

console.log(title, width, height, item1. item2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

options 的属性 size 是另一个对象,属性 items 是另一个数组。

# 智能函数参数

有时,一个函数有很多参数,其中大部分的参数都是可选的。对可能不需要提供的参数设置默认值。

一般不可能写成:

function showMenu(title = "Untitled", width = 200, height = 100, items = []) {
  // ...
}

showMenu("My Menu", undefined, undefined, ["Item1", "Item2"])
1
2
3
4
5

🌰 例子 / 使用解构赋值,将函数参数写成对象,传入的参数也是一个对象:

let options = {
  title: "My menu",
  items: ["Item1", "Item2"]
};

function showMenu({title = "Untitled", width = 200, height = 100, items = []}) {
  // title, items – 提取于 options,
  // width, height – 使用默认值
  console.log( `${title} ${width} ${height}` ); // My Menu 200 100
  console.log(items); // Item1, Item2
}

showMenu(options) 
1
2
3
4
5
6
7
8
9
10
11
12
13

更详细的语法与结构相同:

function({
  incomingProperty: varName = defaultValue
  ...
})
1
2
3
4

对于参数中的对象,属性 incomingProperty 对应的变量是 varName ,默认值是 defaultValue

如果想要所有参数对象属性都使用默认值,要传入一个空的对象:

showMenu({})
1

要什么都不传,可以为该 参数对象设一个默认值

function showMenu({ title = "Menu", width = 100, height = 200 } = {}) {
  alert( `${title} ${width} ${height}` );
}

showMenu()
1
2
3
4
5

# 解构总结

  • 解构赋值可以立即将一个对象或数组映射到多个变量上。

  • 解构数组: let [item1 = default, item2, ...rest] = array 。数组的第一个元素被赋值给 item1 ,第二个元素被赋值给 item2 ,剩下的所有元素被复制到另一个数组 rest 。`

  • 解构对象: let {prop : varName = default, ...rest} = object 。属性 prop 会被赋值给变量 varName ,如果没有这个属性的话,就会使用默认值 default 。没有对应映射的对象属性会被复制到 rest 对象。

  • 嵌套解构:等号左侧必须和等号右侧有相同的结构。

# 解构实例

# 获取最大值的对象属性

新建一个函数 topSalary(salaries) ,返回收入最高的人的姓名。

  • 如果 salaries 是空的,函数应该返回 null
  • 如果有多个收入最高的人,返回其中任意一个即可。
let salaries = {
  "John": 100,
  "Pete": 300,
  "Mary": 250
};
1
2
3
4
5
点击查看
function topSalary(salaries) {
	let maxSalary = 0
  let maxName = null
  
  for (let [name, salary] of Object.entries(salaries)){
  	if(maxSalary < salary){ 
    	maxSalary = salary
      maxName = name}
  }
  return maxName
}

console.log(topSalary(salaries))
1
2
3
4
5
6
7
8
9
10
11
12
13
📢 上次更新: 2022/09/02, 10:18:16