解构赋值是一种特殊的语法,它允许我们将数组或则对象“解压”到一堆变量里面。
数组解构
我们可以将数组“解压”到变量中去,例如:
// we have an array with the name and surname
let arr = ["Ilya", "Kantor"]
// destructuring assignment
let [firstName, surname] = arr;
alert(firstName); // Ilya
alert(surname); // Kantor
当它与数组的一些方法组合起来会很方便,例如:
let [firstName, surname] = "Ilya Kantor".split(' ');
解构不影响元原数组
解构数组其实就是将数组元素赋值到新的变量里,而原数组并不会被影响,解构原理如下例子:
// let [firstName, surname] = arr;
let firstName = arr[0];
let surname = arr[1];
解构只是上面例子的简写形式
忽略指定元素
在解构数组的时候,如果不需要某些元素,我们可以手动忽略掉,例如:
// first and second elements are not needed
let [, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
alert( title ); // Consul
解构任何可迭代对象
我们除了解构数组外,任何可迭代对象都是可以被解构的,例如String,Map,Set
let [a, b, c] = "abc"; // ["a", "b", "c"]
let [one, two, three] = new Set([1, 2, 3]);
在左边指定属性
let user = {};
[user.name, user.surname] = "Ilya Kantor".split(' ');
alert(user.name); // Ilya
使用Obejct.entries()进行遍历解构
Obejct.entries()方法以数组的格式返回对象的属性名和值,我们可以使用它进行遍历解构,例如:
let user = {
name: "John",
age: 30
};
// loop over keys-and-values
for (let [key, value] of Object.entries(user)) {
alert(`${key}:${value}`); // name:John, then age:30
}
对于Map也是一样的,例如:
let user = new Map();
user.set("name", "John");
user.set("age", "30");
for (let [key, value] of user.entries()) {
alert(`${key}:${value}`); // name:John, then age:30
}
解构到剩余的变量里
如果我们需要解构多个变量里,我们可以不一一写出这些变量名,使用“...”来接收解构的元素,例如:
let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
alert(name1); // Julius
alert(name2); // Caesar
alert(rest[0]); // Consul
alert(rest[1]); // of the Roman Republic
alert(rest.length); // 2
默认值
如果我们要解构的数组为空,那么用于接收解构结果的参数的值默认为undefined,例如:
let [firstName, surname] = [];
alert(firstName); // undefined
当然,我们可以手动设置默认值,例如:
// default values
let [name = "Guest", surname = "Anonymous"] = ["Julius"];
alert(name); // Julius (from array)
alert(surname); // Anonymous (default used)
// runs only prompt for surname
let [name = prompt('name?'), surname = prompt('surname?')] = ["Julius"];
alert(name); // Julius (from array)
alert(surname); // whatever prompt gets
对象解构
对象解构会默认将属性名解构到对应相同名字的变量中,若名字不同则为undefined,例如:
let options = {
title: "Menu",
width: 100,
height: 200
};
let {title, width, height} = options;
alert(title); // Menu
alert(width); // 100
alert(height); // 200
当然打乱顺序也无所谓,因为它会自动根据属性名关联,例如:
// changed the order of properties in let {...}
let {height, width, title} = { title: "Menu", height: 200, width: 100 }
接受变量名修改
如果你想自定义解构后的变量名,你可以这样做:let options = {
title: "Menu",
width: 100,
height: 200
};
// { sourceProperty: targetVariable }
let {width: w, height: h, title} = options;
// width -> w
// height -> h
// title -> title
alert(title); // Menu
alert(w); // 100
alert(h); // 200
这时候width就被修改为w了,我们就可以使用修改后的变量名w
默认值
跟数组解构一样,对象解构也可以设置默认值,例如:
也可以使用函数设置默认值,例如:
let options = {
title: "Menu"
};
let {width = 100, height = 200, title} = options;
alert(title); // Menu
alert(width); // 100
alert(height); // 200
也可以使用函数设置默认值,例如:
let options = {
title: "Menu"
};
let {width = prompt("width?"), title = prompt("title?")} = options;
alert(title); // Menu
alert(width); // (whatever you the result of prompt is)
跟上面的冒号方式修改接受变量名结合起来就是:
let options = {
title: "Menu"
};
let {width: w = 100, height: h = 200, title} = options;
alert(title); // Menu
alert(w); // 100
alert(h); // 200
剩余接受变量操作(rest)
let options = {
title: "Menu",
height: 200,
width: 100
};
let {title, ...rest} = options;
// now title="Menu", rest={height: 200, width: 100}
alert(rest.height); // 200
alert(rest.width); // 100
没有let情况
let title, width, height;
// error in this line
{title, width, height} = {title: "Menu", width: 200, height: 100};
因为Javascript会把{...}里的内容当做代码块处理,比如这样:
{
// a code block
let message = "Hello";
// ...
alert( message );
}
为了解决这种问题,我们可以使用小括号把解构代码括起来,例如:
let title, width, height;
// okay now
({title, width, height} = {title: "Menu", width: 200, height: 100});
alert( title ); // Menu
嵌套解构
如果一个对象或者数组里嵌套了其他对象或数组,我们可以声明对应的结构的变量来接收解构结果,例如:
let options = {
size: {
width: 100,
height: 200
},
items: ["Cake", "Donut"],
extra: true // something extra that we will not destruct
};
// destructuring assignment on multiple lines for clarity
let {
size: { // put size here
width,
height
},
items: [item1, item2], // assign items here
title = "Menu" // not present in the object (default value is used)
} = options;
alert(title); // Menu
alert(width); // 100
alert(height); // 200
alert(item1); // Cake
alert(item2); // Donut
// take size as a whole into a variable, ignore the rest
let { size } = options;
利用解构来设置函数参数
设想一下,如果一个函数有多个参数,并且有些参数还是可选的,那我们应该怎样来调用,例如这样:
function showMenu(title = "Untitled", width = 200, height = 100, items = []) {
// ...
}
showMenu("My Menu", undefined, undefined, ["Item1", "Item2"]);
但是这样写太麻烦且可读性差,因此我们可以使用解构的方式来填充参数,例如:
// we pass object to function
let options = {
title: "My menu",
items: ["Item1", "Item2"]
};
// ...and it immediately expands it to variables
function showMenu({title = "Untitled", width = 200, height = 100, items = []}) {
// title, items – taken from options,
// width, height – defaults used
alert( `${title} ${width} ${height}` ); // My Menu 200 100
alert( items ); // Item1, Item2
}
showMenu(options);
或者自定义接受变量名:
let options = {
title: "My menu",
items: ["Item1", "Item2"]
};
function showMenu({
title = "Untitled",
width: w = 100, // width goes to w
height: h = 200, // height goes to h
items: [item1, item2] // items first element goes to item1, second to item2
}) {
alert( `${title} ${w} ${h}` ); // My Menu 100 200
alert( item1 ); // Item1
alert( item2 ); // Item2
}
showMenu(options);
showMenu({});
showMenu(); // this would give an error
为了解决这种问题,我们可以在声明函数的时候就设置默认值,例如:
// simplified parameters a bit for clarity
function showMenu({ title = "Menu", width = 100, height = 200 } = {}) {
alert( `${title} ${width} ${height}` );
}
showMenu(); // Menu 100 200