解构赋值
来源
当我们将对象或者数组传递给函数时,可能并不需要全部的数据,只需要其中的一部分,解构赋值就可以将对象或者数组“拆包”至一系列变量中。
数组解构
// 我们有一个存放了名字和姓氏的数组
let arr = ["John", "Smith"]
// 解构赋值
// 设置 firstName = arr[0]
// 以及 surname = arr[1]
let [firstName, surname] = arr;
alert(firstName); // John
alert(surname); // Smith
//也可结合split函数(或者其他返回值为数组的函数)使用:
let [firstName, surname] = "John Smith".split(' ');
alert(firstName); // John
alert(surname); // Smith
细节:
- 解构赋值并没有破坏原先的数组
以上写法等同于:let firstName = arr[0]; let surname = arr[1];
- 赋值时,如果不想要原先数组中的某一个元素,可以用逗号隔开:
// 不需要第二个元素 let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]; alert( title ); // Consul
- 等号右侧可以是任何可迭代的对象。
let [a, b, c] = "abc"; // ["a", "b", "c"] let [one, two, three] = new Set([1, 2, 3]);
- 等号左侧可以是任何“可以被赋值”的东西,如一个对象的属性
let user = {}; [user.name, user.surname] = "John Smith".split(' '); alert(user.name); // John alert(user.surname); // Smith
- 与entries方法一同使用,遍历并获取“键值对”
let user = { name: "John", age: 30 }; // 使用循环遍历键—值对 for (let [key, value] of Object.entries(user)) { alert(`${key}:${value}`); // name:John, age:30 } //用Map更简单,因为Map是可迭代的,并且是以[key,value]对的形式迭代的 let user = new Map(); user.set("name", "John"); user.set("age", "30"); // Map 是以 [key, value] 对的形式进行迭代的,非常便于解构 for (let [key, value] of user) { alert(`${key}:${value}`); // name:John, then age:30 }
- 利用解构赋值来交换两个变量的值
let a=3; let b=5; [b,a]=[a,b]; alert('${a} ${b}')
如果等号左边变量个数和右边元素个数不相等时:
//右边更长时,后面的元素不会被复制然后赋值
let [name1, name2] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
alert(name1); // Julius
alert(name2); // Caesar
// 其余数组项未被分配到任何地方
//也可以用 [...变量名] 来接收剩余的元素,
let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
// rest 是包含从第三项开始的其余数组项的数组
alert(rest[0]); // Consul
alert(rest[1]); // of the Roman Republic
alert(rest.length); // 2 rest是一个数组
//如果左边更长时,缺少对应值的变量会被赋值undefined
let [firstName, surname] = [];
alert(firstName); // undefined
alert(surname); // undefined
//也可以设置默认值,如果缺少对应值的话,填入默认值
let [name = "Guest", surname = "Anonymous"] = ["Julius"];
alert(name); // Julius(来自数组的值)
alert(surname); // Anonymous(默认值被使用了)
//默认值可以是更加复杂的表达式,甚至可以是函数
let [name = prompt('name?'), surname = prompt('surname?')] = ["Julius"];
//默认表达式/函数只会在缺少对应值时运行,所以这儿只会运行surname的prompt
alert(name); // Julius(来自数组)
alert(surname); // 你输入的值
对象解构
let options = {
title: "Menu",
width: 100,
height: 200
};
let {title, width, height} = options;
//对象解构赋值时,变量的顺序并不重要,因为左边的变量名就是右边的属性名
//let {height, width, title} =options。等价于上面那句
alert(title); // Menu
alert(width); // 100
alert(height); // 200
//如果要把值赋值给另一个名字的变量,需要用冒号设置对应的变量名:
let options = {
title: "Menu",
width: 100,
height: 200
};
//用冒号指定变量名 格式{对象中的属性名:指定的变量名}
let {width: w, height: h, title} = options;
alert(title); // Menu
alert(w); // 100
alert(h); // 200
//对于缺失的属性,也可以用=设置默认值
let options = {
title: "Menu"
};
let {width = prompt("width?"), title = prompt("title?")} = options;
alert(title); // Menu
alert(width); // (prompt 的返回值)
//也可以给指定的变量名设置默认值 let {width: w=100, title} = options;
//剩余模式同上面的数据结构一样
嵌套结构
如果一个对象或数组嵌套了其他的对象和数组,我们可以在等号左侧使用更复杂的模式来提取更深层的数据。
//options对象中,size是另一个对象,items是另一个数组
let options = {
size: {
width: 100,
height: 200
},
items: ["Cake", "Donut"],
extra: true
};
// 我们用相同的结构接收
let {
size: { // 把 size 赋值到这里 size本身是没有值的,alert(size)不会输出内容
width,
height
},
items: [item1, item2], // 把 items 赋值到这里
title = "Menu" // 在对象中不存在(使用默认值)
} = options;
//可以直接使用,比使用对象中的属性要方便
alert(title); // Menu
alert(width); // 100
alert(height); // 200
alert(item1); // Cake
alert(item2); // Donut