- 数组的解构赋值
- 对象的解构赋值
- 字符串的解构赋值
- 数值和布尔值的解构赋值
- 函数参数的解构赋值
数组的解构赋值
// ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)
{
// es5
let a = 1;
let b = 2;
let c = 3;
console.log(a, b, c); // 1 2 3
}
{
// es6
let [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1 2 3
}
// 可以从数组中提取值,按照对应位置,对变量赋值。
// 本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值
{
let [a, [[b], c]] = [1, [[2], 3]];
console.log(a, b, c); // 1 2 3
}
{
let [, , c] = [1, 2, 3];
console.log(c); // 3
}
{
let [a, , c] = [1, 2, 3];
console.log(a, c); // 1 3
}
{
let [a, b, ...rest] = [1, 2, 3, 4, 5, 6];
console.log(a, b, rest); // 1 2 [3, 4, 5, 6]
}
{
// 如果解构不成功,变量的值就等于undefined
let [a, b, ...c] = ["Di-got"];
console.log(a, b, c); // Di-got undefined []
// 另一种情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。
let [d, e] = [1, 2, 3];
console.log(d, e); // 1 2
let [f, [g], h] = [1, [2, 3], 4];
console.log(f, g, h); // 1 2 4
}
{
// 默认值
let [x = 1, y = x] = []; // x=1; y=1
let [x = 1, y = x] = [2]; // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = []; // ReferenceError: y is not defined
// x用y做默认值时,y还没有声明。
}
对象的解构赋值
// 对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
// 对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
{
let { a, b } = { a: 1, b: 2 };
console.log(a, b); // 1 2
}
{
// 变量没有对应的同名属性,导致取不到值,最后等于undefined(解构失败,变量的值等于undefined。)
let { a } = { b: 2 };
console.log(a); // undefined
}
{
// 默认值
let { x = 3 } = {};
console.log(x); // 3
let { x, y = 5 } = { x: 1 };
console.log(x, y) // 1 5
let { x: y = 3 } = {};
console.log(y); // 3
let { x: y = 3 } = { x: 5 };
console.log(y) // 5
let { message: msg = 'Something went wrong' } = {};
console.log(msg); // "Something went wrong"
}
{
// 已经声明的变量用于解构赋值
// 错误写法
let x;
{x} = {x: 1}; // SyntaxError: syntax error
// JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。
// 正确的写法 (将整个解构赋值语句,放在一个圆括号里面,就可以正确执行)
let x;
({x} = {x: 1});
// 由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。
let arr = [1, 2, 3];
let { 0: first, [arr.length - 1]: last } = arr;
console.log(first, last); // 1 3
}
{
let metaData = {
title: 'wcd',
test: [{
title: 'test',
desc: 'description'
}]
}
let { title: esTitle, test: [{ title: cnTitle }] } = metaData;
console.log(esTitle, cnTitle); // wcd test
}
字符串的解构赋值
// 字符串也可以解构赋值
// 字符串被转化成了一个类似数组的对象
{
const [a, b, c, d, e] = "hello";
console.log(a, b, c, d, e); // h e l l o
}
{
// 类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。
let { length: len } = "hello";
console.log(len); // 5
}
数值和布尔值的解构赋值
// 解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。
// 注意:解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。
{
let { toString: s } = 123;
console.log(s === Number.prototype.toString); // true
}
{
let { toString: s } = true;
console.log(s === Boolean.prototype.toString); // true
}
函数参数的解构赋值
// 函数的参数也可以使用解构赋值
{
[[1, 2], [3, 4]].map(([a, b]) => a + b); // [3, 7]
}
// 函数参数的解构也可以使用默认值
// 函数moveOne的参数是一个对象,通过对这个对象进行解构,得到变量x和y的值。如果解构失败,x和y等于默认值。
{
function moveOne({ x = 0, y = 0 } = {}) {
return [x, y];
}
moveOne({ x: 3, y: 8 }); // [3, 8]
moveOne({ x: 3 }); // [3, 0]
moveOne({}); // [0, 0]
moveOne(); // [0, 0]
}
// 函数move的参数指定默认值,而不是为变量x和y指定默认值,所以会得到与前一种写法不同的结果。
{
function moveTwo({ x, y } = { x: 0, y: 0 }) {
return [x, y];
}
moveTwo({ x: 3, y: 8 }); // [3, 8]
moveTwo({ x: 3 }); // [3, undefined]
moveTwo({}); // [undefined, undefined]
moveTwo(); // [0, 0]
}
// undefined就会触发函数参数的默认值。
{
[1, undefined, 3].map((x = "yes") => x); // [ 1, 'yes', 3 ]
}