📶 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