解构赋值
约 1380 字大约 5 分钟
2025-03-12
在 JavaScript 中,解构赋值是一种从数组或对象中提取值,并将它们赋给变量的简洁方法。使用解构赋值可以让你方便地对多个值进行分解、组合。
一、数组
// 数组的解构赋值
// 普通常见
const [x, y, z, ...other] = [1, 2, 3, 4, 5, 6];
console.log(x); // 1
console.log(y); // 2
console.log(z); // 3
console.log(other); // [4, 5, 6]
// 深层解构
const [x, y, [z], a] = [1, 2, [3, 4], 5, 6];
console.log(x); // 1
console.log(y); // 2
console.log(z); // 3
console.log(a); // 5
// 缺省情况
const [, y, z] = [1, 2, 3];
console.log(y); // 2
console.log(z); // 3
// 把数组当对象解构,起别名
const { 1: a, 2: b, ...other } = [1, 2, 3, 4, 5, 6];
console.log(a); // 2
console.log(b); // 3
console.log(other); // {0: 1, 3: 4, 4: 5, 5: 6}
二、对象
// 对象的结构赋值
const { name, age, sex, ...other } = {
name: "Alice",
age: 25,
sex: "man",
habbit: "music",
};
console.log(name); // "Alice"
console.log(age); // 25
console.log(other); // { habbit: 'music' }
// 起别名
const { name, sex: xxx } = {
name: "Alice",
age: 25,
sex: "man",
habbit: "music",
};
console.log(xxx); // man
console.log(sex); // undefined
// 深层解构
const {
name,
desc: { sex, habbit },
} = { name: "Alice", age: 25, desc: { sex: "man", habbit: "music" } };
console.log(sex); // man
console.log(habbit); // music
三、字符串
字符串也可以解构赋值。此时的字符串被当做数组来处理。
const [a, b, c, d, e] = "hello";
a; // "h"
b; // "e"
c; // "l"
d; // "l"
e; // "o"
四、数值和布尔值
解构赋值时,如果等号右边是数值和布尔值,则被当做对象处理。
let { toString: sss } = 123; // 将toString 赋给 sss
sss === Number.prototype.toString; // true
let { toString: sss } = true; // 将toString 赋给 sss
sss === Boolean.prototype.toString; // true
上面代码中,数值和布尔值的原型链上都有toString
属性,因此变量sss
都能取到值。
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined
和null
无法转为对象,所以对它们进行解构赋值,都会报错。
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
五、函数参数
函数的参数也可以使用解构赋值。
function add([x, y]) {
return x + y;
}
add([1, 2]); // 3
上面代码中,函数add
的参数表面上是一个数组,但在传入参数的那一刻,数组参数就被解构成变量x
和y
。对于函数内部的代码来说,它们能感受到的参数就是x
和y
。
下面是另一个例子。
[
[1, 2],
[3, 4],
].map(([a, b]) => a + b); // [ 3, 7 ]
函数参数的解构也可以使用默认值。
function move({ x = 0, y = 0 } = {}) {
return [x, y];
}
move({ x: 3, y: 8 }); // [3, 8]
move({ x: 3 }); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
上面代码中,函数move
的参数是一个对象,通过对这个对象进行解构,得到变量x
和y
的值。如果解构失败,x
和y
等于默认值。
注意,下面的写法会得到不一样的结果。
function move({ x, y } = { x: 0, y: 0 }) {
return [x, y];
}
move({ x: 3, y: 8 }); // [3, 8]
move({ x: 3 }); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]
上面代码是为函数move
的参数指定默认值,而不是为变量x
和y
指定默认值,所以会得到与前一种写法不同的结果。
undefined
就会触发函数参数的默认值。
[1, undefined, 3].map((x = "yes") => x); // [ 1, 'yes', 3 ]
六、常见用途
1、交换变量的值
let x = 1;
let y = 2;
[x, y] = [y, x];
上面代码交换变量x
和y
的值,这样的写法不仅简洁,而且易读,语义非常清晰。
2、从函数返回对象里获取多个值
函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。
// 返回一个数组
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
// 返回一个对象
function example() {
return {
foo: 1,
bar: 2,
};
}
let { foo, bar } = example();
3、函数形参
解构赋值可以方便地将一组参数与变量名对应起来。
// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
4、提取 JSON 数据
解构赋值对提取 JSON 对象中的数据,尤其有用。
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309],
};
let { id, status, data: number } = jsonData;
console.log(id, status, number); // 42, "OK", [867, 5309]
上面代码可以快速提取 JSON 数据的值。
5、函数参数的默认值
jQuery.ajax = function (
url,
{
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
} = {}
) {
// ... do stuff
};
指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || 'default foo';
这样的语句。
6、遍历 Map 结构
任何部署了 Iterator 接口的对象,都可以用for...of
循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。
const map = new Map();
map.set("first", "hello");
map.set("second", "world");
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world
如果只想获取键名,或者只想获取键值,可以写成下面这样。
// 获取键名
for (let [key] of map) {
// ...
}
// 获取键值
for (let [, value] of map) {
// ...
}
7、模块的按需导入
加载模块时,按照需要导入。解构赋值使得输入语句非常清晰。
const { SourceMapConsumer, SourceNode } = require("source-map");
更新日志
e7112
-1于