📶 JavaScript 解构赋值
在 JavaScript 中最常用的两种数据结构是 对象 Object 和 数组 Array。要将它们传递给函数,函数可能不需要 整个对象或者数组。
解构赋值 是一种特殊的语法,它使我们可以将数组或对象「拆包」至一系列变量中,因为有时这样更方便。
# 数组解构
🌰 例子 / 将数组结构到变量:
let arr = ["John", "Smith"]
let [firstName, surname] = arr
// 相当于 firstName = arr[0], surname = arr[1]
 2
3
4
在新的变量上进行的操作不会影响到原来的数组元素。
🌰 例子 / 对字符串使用解构:
let [firstName, surname] = 'John Smith'.split(' ')
 注意
「解构」不意味着「破坏」:解构通过将结构中的各元素 复制 到变量中来达到「解构」的目的。但数组本身是没有被修改的。
🌰 例子 / 使用「 , 」 逗号选择性赋值::
let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
// 第二个元素不需要,使用逗号跳过,并且剩下的元素没有对应变量也会被忽略
 2
🌰 例子 / 等号的右侧可以是 任何可迭代对象:
let [a, b, c] = "abc"; // ["a", "b", "c"]
let [one, two, three] = new Set([1, 2, 3]);
 2
🌰 例子 / 等号的左侧可以是任何「可以被赋值的」:
let user = {}
[user.firstName, user.surname] = 'John Smith'.split(' ') 
 2
🌰 例子 / 配合  .entries  循环(只循环其中特定的值):
let user = {
  name: 'Simon'.
  age: 30,
  gender: 'male'
}
for(let [key, value] of Object.entries(user)) {
  console.log(`${key}: ${name}`)
}
 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}`)
}
 2
3
4
5
6
7
8
🍎 🌰 例子 / 使用解构赋值交换变量:
let guest = "Jane";
let admin = "Pete";
[guest, admin] = [admin, guest]
 2
3
4
创建了一个由两个变量组成的临时数组,并且立即以交换了的顺序对其进行了解构。这样解决两个及以上的变量的交换一下就简单了。
# …  剩余项
 当不设置相应的变量接收对应的数组项,这里剩余的数组项可以使用  …  加一个参数来接收。
🌰 例子:
let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
console.log(rest) // ["Consul", "of the Roman Republic"]
 2
3
rest的值就是数组中剩下的元素组成的 数组。
# 默认值
如果数组比等号左边的变量列表短,这里也不会出现报错。缺少的值被认为是  undefined :
🌰 例子:
let [firstName, surname] = [];
console.log(firstName); // undefined
console.log(surname); // undefined
 2
3
4
对于可能没有的值,可以设置一个默认值,避免出现  undefined 。
🌰 例子:
let [name = "Guest", surname = "Anonymous"] = ["Julius"];
console.log(name, surname) // "Julius", "Anonymous"
 2
默认值可以是 更加复杂的表达式 甚至可以是 函数调用,这些表达式或函数只会在这个变量 未被赋值的时候 才会被计算。
🌰 例子 / 使用函数作为默认值:
let [name = prompt('name?'), surname = prompt('surname?')] = ["Julius"];
console.log(name, surname)
 2
3
这样当
surname没有提供值时,会发起输入框。
# 对象解构
基本语法:
let {var1, var2} = {var1: ..., var2: ...}
 在等号右侧应该有 一个已经存在的对象,等号左侧包含了对象 相应属性的一个类对象「模式(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
 2
3
4
5
6
7
8
9
10
🌰 例子 / 等号左边的模式不需要按照对象中的顺序也可以,会自动对应上。
let {height, width, title} = { title: "Menu", height: 200, width: 100 }
 🌰 例子 / 等号左侧的模式可以更加复杂,并且指定了属性和变量之间的映射关系。
要把一个属性赋值给另一个名字的变量,比如把  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)
 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;
 2
3
4
5
🌰 例子 / 默认值可以为任意表达式或函数调用,会在未提供对应的值时才会被计算 / 调用。
let options = {
  title: "Menu"
};
let {width = prompt("width?"), title = prompt("title?")} = options;
 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)
 2
3
4
5
6
7
8
9
🌰 例子 / 只提取所需的内容:
let options = {
  title: "Menu",
  width: 100,
  height: 200
};
// 仅提取 title 作为变量
let { title } = options;
 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 }
 2
3
4
5
6
7
8
注意
()  的使用:并且要注意在 JavaScript 中  { ... }  中当做一个 代码块。这样的代码块可以用于对语句分组,就是说  { ... }  中也可以  let  声明变量并且使用。为了在对象解构时,需要 JavaScript 认为 这不是  { }  代码块而是对象 ,所以要用  ( ... )  括号包起来(在箭头函数中返回对象时同样有用到这个原理)
let title, width, height;
({title, width, height} = {title: "Menu", width: 200, height: 100});
 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)
 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) 
 2
3
4
5
6
7
8
9
10
11
12
13
更详细的语法与结构相同:
function({ incomingProperty: varName = defaultValue ... })1
2
3
4对于参数中的对象,属性
incomingProperty对应的变量是varName,默认值是defaultValue。
如果想要所有参数对象属性都使用默认值,要传入一个空的对象:
showMenu({})
 要什么都不传,可以为该 参数对象设一个默认值:
function showMenu({ title = "Menu", width = 100, height = 200 } = {}) {
  alert( `${title} ${width} ${height}` );
}
showMenu()
 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))
 2
3
4
5
6
7
8
9
10
11
12
13
