0%

Javascript 变量的解构赋值

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

对象/数组逐个对应表达式,或成对象字面量和数组字面量。提供了一种简单的定义一个特定的数据组的方法。解构表达式在左边定义了要从原变量中取出什么变量。

解构原理

解构是ES6提供的语法糖,其实是正对”可迭代对象“的Iterator接口,通过“遍历器”按顺序获取对应的值进行赋值。

解构数组

假设有数组:

1
2
const fruits = ['apple', 'banana', 'strawberry'];
const [a, b] = fruits;

我们从其中解构第一个和第三个,可以在变量声明时并赋值:

1
const [a, , b] = fruits;

也可以先声明然后进行赋值:

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

设定默认值

为了防止从数组中取出值为undefined的对象,可以在表达式左侧的数组中为任意对象预设默认值:

1
2
let a, b;
[a = 5, b = 7] = [1]; // a 的值为1, b 的值为7.

利用解构交换变量

可以用解构的特性,直接交换两个变量的值。例如:

1
2
let a = 1, b = 2;
[a, b] = [b, a] // a 的值为2, b 的值为1

将剩余元素赋值给一个变量

当解构一个数组时,可以使用剩余模式,将数组剩余部分赋值为一个变量。注意,如果剩余元素右侧有逗号,会抛出SyntaxError,因为剩余元素必须是左侧数组的最后一个元素。

1
2
const fruits = ['apple', 'banana', 'strawberry'];
const [a, ...b] = fruits; // a 为 apple, b 为['banana', 'strawberry']

数组的对象形式解构

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

1
2
3
const arr = [1, 2, 3, 4, 5];

const {0:first, [arr.length - 1]: last} = arr; // first 值 1,last 值 5.

解构对象

对象的解构赋值用于从一个对象取值,相当于将目标对象自身的所有可遍历的(enumerable)、但尚未被读取的属性,分配到指定的对象上面。所有的键和值,都会拷贝到新对象上面。

基本赋值:

1
2
3
4
5
6
const obj = {
a: 1,
b: 2,
c: 3,
};
const {a, b} = obj; // a 值 1, b 值 2

无申明赋值(注意外面的括号,如果没有括号的话,左边的{a, b}会被认为是一个块):

1
2
let a, b;
({a, b} = obj); // a 值 1, b 值 2

给新的变量名赋值

在解构赋值的时候,可以给提取的对象属性一个不同的新的名字:

1
2
3
4
5
6
const obj = {
a: 1,
b: 2,
c: 3,
};
const {a: newA, b: newB} = obj; // newA 值 1, newB 值 2.

给新的变量命名并提供默认值:

1
const {a: newA = 2, b: newB = 3, d: newD = 4} = obj; // newA 值 1, newB 值 2, newD 值 4

函数参数默认值

现有一个方法:

1
2
3
function drawChart({size = 'big', cords = {x: 0, y: 0}, radius = 25} = {}) {
console.log(size, cords, radius);
}

这样,可以在调用的时候传递参数:

1
2
drawChart({cords: {x: 18}, radius: 30});
// 输出:big, {x: 18, y: 0}, 30

对象属性计算名和解构

计算属性名,也可以被解构:

1
2
3
4
5
6
7
8
const obj = {
a: 1,
b: 2,
c: 3,
};
let name = 'b';
name = String.fromCharCode(name.charCodeAt() + 1);
const {[name]: str} = obj; // name 动态修改为'c', 所以str的值应当为3

解构对象时会查找原型链

如果解构的属性不在对象自身,将从原型链中查找。

1
2
3
4
5
6
const obj = {self: 1};
obj.__proto__.prot = 2;

const obj1 = {self: 2};
const {self, prot} = obj1;
console.log(self, prot); // 输出:2, 2(prot访问到了原型链)

解构嵌套对象/数组

保持对象的层级,即可解构嵌套对象

1
2
3
4
5
6
7
8
9
10
11
const obj = {
a: 1,
b: 2,
c: 3,
d: {
e: 4,
f: 5,
g: [2, 3, 4],
}
};
const {a: newA, b: newB, d: {e: newE, g: [first]}} = obj; // 输出: 1 2 4 2

解构嵌套数组,需要依次对应数组的个数:

1
2
const arr = [1, [2, 3], 4, 5];
const [a, [...b]] = arr; // a 值 1, b 值 [2, 3]

解构String/Map/Set

任何部署了Iterator接口的对象,都可以用for...of循环遍历。可以作为“类数组”来进行解构。

String

ES6为字符串添加了遍历接口,使得字符串可以被for...of来循环:

1
2
3
4
const str = 'abcde';
for (let i of str) {
console.log(i); // 依次输出:a、b、c、d、e
}

所以,也可以被解构:

1
2
const str = 'abcdefg';
const [first, second] = str; // first 值 a, second 值 b

Map

Map结构原生支持Iterator接口,可以直接使用解构语法:

1
2
3
4
const m = new Map();
m.set('a', 1).set('b', 2);
const [c, d] = m;
console.log(c, d); // c 值 ['a', 1], d 值 ['b', 2]

可以结合for...of和解构,可以很方便的遍历Map结构:

1
2
3
4
5
const m = new Map();
m.set('a', 1).set('b', 2);
for( let [key, value] of m) {
console.log(key, value); // 依次输出:a, 1; b, 2
}

Set

Set结构类似于数组,但是成员都是唯一的,没有重复的值。Set结构也原生支持Iterator接口,可以使用解构语法:

1
2
3
4
const s = new Set([1, 2, 3, 3]);
const [a, b] = s;
console.log(s); // 输出 Set {1, 2, 3}
console.log(a, b); // a 值 1, b 值 2

解构常用,但一些偏门的用法还是不晓得,很不明白面试为什么卡这中细小的知识点。

never mind

学到了就是自己的,整理下,我不就知道了么~😎

参考: