跳至主要內容

03【解构赋值】

约 2464 字大约 8 分钟...

03【解构赋值】

1.数组的解构赋值

1.1 原理

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

以前,为变量赋值,只能直接指定值。

let a = 1;
let b = 2;
let c = 3;

ES6 允许写成下面这样。

let [a, b, c] = [1, 2, 3];

上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。

  1. 模式(结构)匹配 [] = [1, 2, 3];

  2. 索引值相同的完成赋值 const [a, b, c] = [1, 2, 3];

  3. 举例

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

1.2 数组解构赋值的默认值

(1)默认值的基本用法

const [a, b] = [];
console.log(a, b);    // undefined undefined

// ---------------------------------------
const [a = 1, b = 2] = [];
console.log(a, b);    // 1 2

(2)默认值的生效条件

只有当一个数组成员严格等于 (===) undefined 时,对应的默认值才会生效。

const [a = 1, b = 2] = [3, 0];        // 3 0
const [a = 1, b = 2] = [3, null];    // 3 null
const [a = 1, b = 2] = [3];            // 3 2

(3)默认值表达式

如果默认值是表达式,默认值表达式是惰性求值的(即:当无需用到默认值时,表达式是不会求值的)

const func = () => {
    return 24;
};

const [a = func()] = [1];    // 1
const [b = func()] = [];    // 24

1.3 数组解构赋值的应用

(1)arguments

function func() {
    const [a, b] = arguments;
    console.log(a, b);    // 1 2
}
func(1, 2);

(2)NodeList

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>NodeList</title>
</head>
<body>
<p>1</p>
<p>2</p>
<p>3</p>
<script>
    const [p1, p2, p3] = document.querySelectorAll('p');
    console.log(p1, p2, p3);
    /*
    <p>1</p>
    <p>2</p>
    <p>3</p>
    */
</script>
</body>
</html>

(3)函数参数的解构赋值

const array = [1, 1];
// const add = arr => arr[0] + arr[1];
const add = ([x = 0, y = 0]) => x + y;
console.log(add(array));    // 2
console.log(add([]));        // 0

(4)交换变量的值

let x = 2, y = 1;

// 原来
let tmp = x;
x = y;
y = tmp;

// 现在
[x, y] = [y, x];
// 理解:[x, y] = [2, 1]
console.log(x, y);
// 1 2

(5)跳过某项值使用逗号隔开

在解构数组时,可以忽略不需要解构的值,可以使用逗号对解构的数组进行忽略操作,这样就不需要声明更多的变量去存值了:

var [a, , , b] = [10, 20, 30, 40];
console.log(a);   // 10
console.log(b);   // 40

上面的例子中,在 a、b 中间用逗号隔开了两个值,这里怎么判断间隔几个值呢,可以看出逗号之间组成了多少间隔,就是间隔了多少个值。如果取值很少的情况下可以使用下标索引的方式来获取值。

(6)剩余参数中的使用

通常情况下,需要把剩余的数组项作为一个单独的数组,这个时候我们可以借助展开语法把剩下的数组中的值,作为一个单独的数组,如下:

var [a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a);     // 10
console.log(b);     // 20
console.log(rest);  // [30, 40, 50]

在 rest 的后面不能有 逗号 不然会报错,程序会认出你后面还有值。...rest 是剩余参数的解构,所以只能放在数组的最后,在它之后不能再有变量,否则则会报错。

1.4 必须要分号的两种情况

// 1. 立即执行函数
// ;(function () { })();
// (function () { })();

// 2. 使用数组解构的时候
// const arr = [1, 2, 3]
const str = 'pink';
[1, 2, 3].map(function (item) {
  console.log(item)
})

let a = 1
let b = 2
  ;[b, a] = [a, b]

console.log(a, b)

2.对象的解构赋值

2.1 原理

对象的解构和数组基本类似,对象解构的变量是在 {} 中定义的。对象没有索引,但对象有更明确的键,通过键可以很方便地去对象中取值。在 ES6 之前直接使用键取值已经很方便了:

var obj = { name: 'imooc', age: 7 };
var name = obj.name;  // imooc
var age = obj.age;    // 7

但是在 ES6 中通过解构的方式,更加简洁地对取值做了简化,不需要通过点操作增加额外的取值操作。

var obj = { name: 'imooc', age: 7 };
var { name, age } = obj;  // name: imooc, age: 7

{} 直接声明 name 和 age 用逗号隔开即可得到目标对象上的值,完成声明赋值操作。

  1. 模式(结构)匹配 {} = {};
  2. 属性名相同的完成赋值 const {name, age} = {name: 'jerry', age: 18};const {age, name} = {name: 'jerry', age: 18};

2.2 对象解构赋值的默认值

  1. 对象的属性值严格等于 undefined 时,对应的默认值才会生效。

  2. 如果默认值是表达式,默认值表达式是惰性求值的。

对象的默认值和数组的默认值一样,只能通过严格相等运算符(===)来进行判断,只有当一个对象的属性值严格等于 undefined,默认值才会生效。

var {a = 10, b = 5} = {a: 3};                 // a = 3, b = 5
var {a = 10, b = 5} = {a: 3, b: undefined};   // a = 3, b = 5
var {a = 10, b = 5} = {a: 3, b: null};        // a = 3, b = null

所以这里的第二项 b 的值是默认值,第三项的 null === undefined 的值为 false,所以 b 的值为 null。

2.3 重命名属性

在对象解构出来的变量不是我们想要的变量命名,这时我们需要对它进行重命名。

var {a:x = 8, b:y = 3} = {a: 2};

console.log(x); // 2
console.log(y); // 3

这里把 a 和 b 的变量名重新命名为 x 和 y。

2.4 对象解构赋值的应用

(1)对象作为函数参数

// 之前
const logPersonInfo = user => console.log(user.name, user.age);
logPersonInfo({name: 'jerry', age: 18});

// 之后
const logPersonInfo = ({age = 21, name = 'ZJR'}) => console.log(name, age);
logPersonInfo({name: 'jerry', age: 18});    // jerry 18
logPersonInfo({});    // ZJR 21

(2)复杂的嵌套(主要是缕清逻辑关系即可)

const obj = {
    x: 1,
    y: [2, 3, 4],
    z: {
        a: 5,
        b: 6
    }
};

// ----------------------------------------------------
const {x, y, z} = obj;
console.log(x, y, z);    // 1 [ 2, 3, 4 ] { a: 5, b: 6 }

// ----------------------------------------------------
const {y: [, y2]} = obj;
console.log(y2);    // 3
console.log(y);        // 报错

// ----------------------------------------------------
const {y: y, y: [, y2]} = obj;
console.log(y2);    // 3
console.log(y);        // [ 2, 3, 4 ]

// ----------------------------------------------------
const {y, y: [, y2], z, z: {b}} = obj;
console.log(y2);    // 3
console.log(y);        // [ 2, 3, 4 ]
console.log(z);        // { a: 5, b: 6 }
console.log(b);        // 6

(3)剩余参数中的使用

在对象的解构中也可以使用剩余参数,对对象中没有解构的剩余属性做聚合操作,生成一个新的对象。

var {a, c, ...rest} = {a: 1, b: 2, c: 3, d: 4}
console.log(a);     // 1
console.log(c);     // 3
console.log(rest);  // { b: 2, d: 4 }

对象中的 b、d 没有被解构,通过剩余参数语法把没有解构的对象属性聚合到一起形成新的对象。

2.5 注意点

(1)如果要将一个已经声明的变量用于解构赋值,必须非常小心。

// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error

上面代码的写法会报错,因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。

// 正确的写法
let x;
({x} = {x: 1});

上面代码将整个解构赋值语句,放在一个圆括号里面,就可以正确执行。关于圆括号与解构赋值的关系,参见下文。

(2)解构赋值允许等号左边的模式之中,不放置任何变量名。因此,可以写出非常古怪的赋值表达式。

({} = [true, false]);
({} = 'abc');
({} = []);

上面的表达式虽然毫无意义,但是语法是合法的,可以执行。

(3)由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。

let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3

上面代码对数组进行对象解构。数组arr0键对应的值是1[arr.length - 1]就是2键,对应的值是3

3.字符串的解构赋值

既可以用数组的形式来解构赋值,也可以用对象的形式来解构赋值。

// 数组形式解构赋值
const [a, b, , , c] = 'hello';
console.log(a, b, c);    // h e o

// 对象形式解构赋值
const {0: a, 1: b, 4: o, length} = 'hello';
console.log(a, b, o, length);    // h e o 5

4.数值和布尔值的解构赋值

只能按照对象的形式来解构赋值。

(会先自动将等号右边的值转为对象)

// 先来复习一下将数值和布尔值转化为对象
console.log(new Number(123));
console.log(new Boolean(true));
// 转化后的对象里没有任何的属性(没有 123 这个属性,也没有 true 这个属性)和方法,
// 所有的属性和方法都在它的继承 __proto__ 中,比如 toString 方法就是继承来的。

// 里面的值只能是默认值,继承的方法倒是可以取到
const {a = 1, toString} = 123;
console.log(a, toString);    // 1 [Function: toString]

// 里面的值只能是默认值,继承的方法倒是可以取到
const {b = 1, toString} = true;
console.log(b, toString);    // 1 [Function: toString]

知道有这回事即可,一般都用不到,因为没太大意义。

5.undefined 和 null 没有解构赋值

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

6.小结

本节讲解了 ES6 解构赋值的使用方法,总结下来一共有以下几点:

  1. 解构赋值一般针对对象和数组,如果解构对象是 undefined 或是 null 都会报错;
  2. 默认值的生效条件是,只有当解构的对象的值是严格模式下的 undefined 的情况下,默认值才会生效;
  3. 可以不借助中间变量来交换两个值;
  4. 在解构复杂的数据解构时,注意声明的对象要和目标的对象有着相同的解构形式,才能去解构目标对象。
已到达文章底部,欢迎留言、表情互动~
  • 赞一个
    0
    赞一个
  • 支持下
    0
    支持下
  • 有点酷
    0
    有点酷
  • 啥玩意
    0
    啥玩意
  • 看不懂
    0
    看不懂
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.8