【ES6】解构赋值 丨 笔记整理

204 阅读7分钟

解构赋值

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

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

数组解构

数组的解构赋值为数组中提取值,按照对应位置,对变量赋值。

let [a,b,c] = [1,2,3];    //可以从数组中提取值,按照对应位置,对变量赋值。
​
//等价于
let a = 1;
let b = 2;
let c = 3;
​
let[first, ,] = ["1","2","3"]    //first=1
let [ , , third] = ["foo", "bar", "baz"];//third=baz
let [x, , y] = [1, 2, 3];  //x =1   y=3
  • 解构不成功,变量的值就等于undefined。
let [a,b,c] = [1,2];
​
console.log(a)    //1
console.log(b)    //2
console.log(c)    //undefined
​
let [a] = []
console.log(a)  //undefined
  • 不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组这种情况下,解构依然可以成功。
let [x,y] = [100,200,300]
​
console.log(x) //100
console.log(y) //200
  • 解构赋值允许指定默认值
let [a = true] = []
console.log(a) //true
​
let [x,y = 'b'] = ['a']
console.log(x) //a
console.log(y) //b

对象解构

解构赋值只要两边结构相同就行,所以对象也是可以解构赋值的。

但是需要注意的是对象和数组的解构有一个很大的区别:对象的属性没有次序,变量必须与属性同名,就能取到正确的值。

let { foo , bar } = { foo: 'aaa', bar: 'bbb' };
console.log(foo)// "aaa"
console.log(bar)// "bbb"//顺序反过来也适用,只要变量和属性同名,就能取到正确的值let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"

解构赋值

  • 将等号后的内容拥有的属性解构出来,赋值给等号前的内容
let {length:len} = "hello";
//length:等号后内容拥有的
//len:赋值给的对象
//将字符串"hello"的length赋值给len
console.log(len); //5
​
​
//创建一个对象,提取它的某一个值赋给另一个变量
var obj={name:"Lily",age:20,sex:"女"}
let {name:stu} = obj;
console.log(stu); //Lily
//必须提取到等号后内容所拥有的属性
let {email:stu1} = obj;
console.log(stu1); //undefined

字符串解构

字符串也可以解构赋值。此时,字符串被转换成一个类似数组的对象。

let [a,b,c,d,e] = "world";
let {length:len} = "world";
console.log(a) //"W"
console.log(b) //"o"
console.log(c) //"r"
console.log(len) //5

函数参数的解构赋值

函数的参数也可以解构赋值

function add([x, y]){   //add的参数是一个数组
  return x + y;
}
​
add([1, 2]); // 3
​
​
//也可以使用默认值//(1)
function fun({x = 0, y = 0} = {}) {
  return [x, y];
}
​
fun({x: 3, y: 8}); // [3, 8]
fun({x: 3}); // [3, 0]
fun({}); // [0, 0]
fun(); // [0, 0]
​
上面代码中,函数fun的参数是一个对象,x和y的默认值都为0,通过对这个对象进行解构,得到变量x和y的值。
如果解构失败,x和y等于默认值。
​
//(2)
function gun({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}
​
gun({x: 3, y: 8}); // [3, 8]
gun({x: 3}); // [3, undefined]
gun({}); // [undefined, undefined]
gun(); // [0, 0]
​
上面代码中,函数gun的参数是一个对象,默认对这个对象进行解构,得到变量x和y的值都是0。
如果解构失败,x和y等于undefined。

(1)和(2)的区别在:(1)是给变量x和y指定默认值,(2)是给函数gun的参数指定默认值。

undefined和null

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。 由于undefined和null无法转为对象,所以对它们进行解构赋值时都会报错

let { prop: x } = undefined; // 报错:TypeError
let { prop: y } = null; // 报错:TypeError//那么,使用undefined和null去解构会怎么样呢?let [a,b,c="小明"] = ["小李","小黄","小张"]    //小李 小黄 小张
let [a,b,c="小明"] = ["小李","小黄",undefined]    //小李 小黄 小明
//undefined不能赋值,则采用默认值
let [a,b,c="小明"] = ["小李","小黄",null]    //小李 小黄 null
//null是一个有效值,因此不会触发默认值,会作为undefined赋值

圆括号的使用

如果变量在解构前就已经定义,此时再去解构就会出现问题。

let foo = 'abc' ;
{ foo } = { foo:'def' };
console.log(foo);

报错:

解构赋值1.png

只需要在解构语句的外面加一个圆括号就可以运行

let foo = 'abc' ;
({ foo } = { foo:'def' })
console.log(foo);    //def

解构赋值的常见应用场景

1.交换变量的值

let x=1,y=2;
[x,y] = [y,x];
console.log(x) //2
console.log(y) //1
//交换了x和y的值,操作简洁清晰

2.从函数返回多个值

一般函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。

// 返回一个数组

function fun() {
  return [1, 2, 3];
}
let [a, b, c] = fun();    //返回了数组[1,2,3]并赋值给[a,b,c]

// 返回一个对象

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

3.函数参数的定义

//有序
function test([x,y,z]){
...
}

test([5,12,7]);

//无序
function test({ x, y, z }) { ... }
test({ y: 12, z: 7, x: 5 });

4.提取JSON数据

JSON

  • 全称是 JavaScript Object Notation,即 JavaScript对象标记法。
  • 是一种轻量级、基于文本的、可读的格式。

语法规则

  • 数组(Array)用方括号(“[]”)表示。
  • 对象(0bject)用大括号(“{}”)表示。
  • 名称/值对(name/value)组合成数组和对象。
  • 名称(name)置于双引号中,值(value)有字符串、数值、布尔值、null、对象和数组
  • 并列的数据之间用逗号(“,”)分隔
let jsonData = {
    "id": "43",
    "name": "Andy",
    "data": [867, 5309]
  };
  
let { id, name, data: number } = jsonData;
  
  console.log(id, name, number);
  // 43, "Andy", [867, 5309]

5.遍历 Map 结构

任何部署了Iterator 接口* 的对象,都可以用for...of循环遍历。Map 结构* 原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。

(*Iterator 迭代器 对集合进行遍历,常用的方法:①hasnext():判断集合是否有下一个元素,有则返回true,没有返回false;②next():获取迭代的下一个元素, 存储String类型的元素)

(Map是一组键值对的结构,具有极快的查找速度,采用“键名(key)”-“键名(value)”的方式存储数据)

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) {
  // ...
}

进阶属性

1.嵌套解构

解构赋值不仅可以解构一层结构,还可以嵌套地解构对象或数组中的内部属性

const user = {
  id: 001,
  name: 'Vita',
  address: {
    city: 'Shanghai',
    zip: 200000
  }
};

const {
  name,
  address: { city, zip }
} = user;

console.log(name); // "Vita"
console.log(city); // "Shanghai"
console.log(zip);  // 200000
  • 注:address 是中间变量,这里并不会声明变量 address,而是直接提取其子属性。

2.函数返回值的结构与重命名

函数返回对象,重命名变量

function getUser() {
  return { id: 1001, username: 'vita' };
}

const { id: userId, username } = getUser();

console.log(userId);  // 1001
console.log(username); // "vita"
  • 用冒号 : 实现属性名与变量名不一致时的赋值。

3.结合数组方法使用解构(高阶函数)

  • forEach 解构
const pairs = [[1, 'one'], [2, 'two'], [3, 'three']];

pairs.forEach(([key, value]) => {
  console.log(`${key}: ${value}`);
});
// 输出:
// 1: one
// 2: two
// 3: three
  • map 配合解构重组结构
const users = [
  { id: 1, name: 'A' },
  { id: 2, name: 'B' }
];

const names = users.map(({ name }) => name);

console.log(names); // ['A', 'B']

4.解构赋值 + rest 剩余运算符组合使用

可以通过rest剩余运算符获取后半部分的对象或数组

  • 对象解构 + 剩余属性
const { a, b, ...rest } = { a: 1, b: 2, c: 3, d: 4 };

console.log(a);    // 1
console.log(b);    // 2
console.log(rest); // { c: 3, d: 4 }
  • 数组解构 + 剩余元素
js
复制编辑
const [first, ...others] = [10, 20, 30, 40];

console.log(first);  // 10
console.log(others); // [20, 30, 40]