解构赋值

概念及示例

官网概念
解构赋值语法是一种 Javascript 表达式。通过解构赋值,可以将 属性 / 值 从 对象 / 数组 中取出,赋值给其他变量。

数值的解构赋值

基本用法
下标对下标。

基础示例

1
2
3
4
5
6
7
let [a, b, c] = [1, 2, 3];
console.log(a, b, c)
// a=1,b=2,c=3

let [d, [e, [f]]] = [4, [5, [6]]];
console.log(d, e, f);
// d=4,e=5,f=6

注解

  • 1、同时声明三个变量:分别为 a,b,c
  • 2、将整数值 1 赋值给变量 a,2 赋值给变量 b,3 赋值给变量 c

这种写法属于” 模式匹配 “,只要模式相同左边的变量就会被赋予相对应的值。

1
2
3
let [,,third] = ["foo","bar","baz"]   //third="baz"(解构部分)
let [a,,b] = [1,2,3] //a=1,b=3(解构部分)
let [x,y] = [1,2,3] //x=1,y=2(不完全解构)

但是如果解构不成功变量的值就等于 undefined

1
let [a,b,...c] = ["1"]   //a=1,b=undefined,c=[]

如果等号右边不是数组(或是可遍历的结构)就会报错。

1
2
let [a, b] = 1
// 1 is not iterable

默认值

数组的解构赋值允许指定默认值

1
let [a = 1] = []; //a = 1

注意:
如果一个数组成员不严格等于 undefined,默认值是不会生效的。
注意 null!== undefined,当数组成员等于 null 时,默认值是不会生效的。
默认值也可以引用解构赋值的其他变量,但是该变量必须已经声明。

对象的解构赋值

基本用法
属性名对属性名。

基础示例

1
2
let { foo:foo ,bar:bar } = { foo:"aaa",bar:"bbb" };
console.log(foo,bar);// aaa bbb

对象解构赋值与数组解构赋值的不同:
数组的元素是按次序排列的,变量的取值是由他的下标决定的;而对象的属性没有次序,变量必须与属性同名才能取到正确的值。

简写(语法糖)

1
let { foo:foo,bar:bar } = { foo:"aaa",bar:"bbb"};

​ 可简写为:

1
let { foo,bar } = { foo:"aaa",bar:"bbb"};

一个名两个用途:既当做配对的属性名,又当做将来单独使用的变量名。

注意:
等号左边要把变量装扮成和要解构的数组或者对象相同的结构
和数组一样,对象解构赋值也可以用于嵌套的解构的对象

如果属性名不一样,必须写成如下例子中一样:

1
2
let { foo:baz } = { foo:"aaa",bar:"bbb"};
//baz="aaa",实际上被赋值的是foo属性的baz变量

默认值
对象的解构赋值也允许指定默认值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var {x = 3} = {};
console.log(x); // 3

var {x, y = 5} = {x: 1};
console.log(x,y);// 1 5

var {x, y = 3} = {};
console.log(x,y);// undefined 3

var {x: y = 3} = {x: 5};
y // 5

var { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"

注意:
默认值生效的条件是,对象的属性值严格等于 undefined
注意 null 不严格等于 undefined 会使默认值不生效
解构失败,变量的值等于 undefined

字符串的解构赋值

字符串也可以解构赋值,这是因为此时字符串被转换成了一个类数组对象。

1
2
3
4
5
const [a, b, c, d, e, f] = "hello"
console.log(a, b, c, d, e, f);// h e l l o undefined

let {length:len} = "hello";
console.log(len);// 5

数值和布尔值的解构赋值

解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。

1
2
3
4
5
let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true

上面代码中,数值和布尔值的包装对象都有 toString 属性,因此变量 s 都能取到值。

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。

由于 undefined 和 null 无法转为对象,所以对它们进行解构赋值,都会报错。

由上的代码可以看出,左边写成 let {toString: s} = 123; 是可以把 Number.prototype.toString 方法的地址值复制一份出来给左边对象结构中的 s,那么以后我们想调用别的父类型(原型对象)上的方法也是不是可以这样做?

eg:查看一个数据是什么类型的:

1
2
3
4
let { toString:objToString } = {};
objToString.call(1) === "[object Number]" //true
objToString.call("") === "[object String]" //true
objToString.call([]) === "[object Array]" //true

可以看到我从 {}.toString 处拿到了 Object 顶级父对象 toString 的地址值然后解构赋值给了 objToString 找到了这个方法是可行的。

函数参数解构赋值的解构赋值

以数组或对象形式传递多个参数,调用时,所有实参值必须也放在一个数组或对象中传入。

1
2
3
4
5
6
7
8
9
function fun([a,b]){
console.log(a+b)
}
fun([1,2]);//3

function fun({a:a,b:b}){
console.log(a+b)
}
fun({a:1,b:2});//3

简写(语法糖)
如果形参名与属性名没必要区分,是相同的名字,也可以只写一个。

1
2
3
4
unction fun({a,b}){
console.log(a+b)
}
fun({a:1,b:2});//3

函数参数的定义和函数参数的默认值

当一个函数内需要多个参数,但调用时不能确定参数有没有,而又要求参数值与函数内变量有对应关系这时就要用到参数解构;指定参数的默认值,就避免了在函数体内部再写 var foo = config.foo || ‘default foo’; 这样的语句。

1
2
3
4
5
6
7
8
9
10
function order(
{zhushi: zs = "香辣鸡腿堡",xiaochi: xc = "薯条薯条",yinliao: yl = "可口可乐"}={})
{
console.log(`您本次点的是:
主食:${zs},
小吃:${xc},
饮料:${yl}
`)
}
order()

实际应用

交换变量的值

1
2
3
4
let x = 1;
let y = 2;

[x, y] = [y, x];

函数返回值

函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回,然后用解构取值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 返回一个数组

function example() {
return [1, 2, 3];
}
let [a, b, c] = example();

// 返回一个对象

function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();

提取 JSON 数据

1
2
3
4
5
6
7
8
9
10
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};

let { id, status, data: number } = jsonData;

console.log(id, status, number);
// 42, "OK", [867, 5309]

输入模块的指定方法

加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。

1
import { 模块 } from "@/xxx/xxx"