ES6之结构赋值

数组的结构赋值

  • 数组的结构赋值是按顺序赋值的
[a,b,c] = [1,2,3]
console.log(a,b,c)
[b,a,c] = [1,2,3]
console.log(a,b,c)
// 123
// 213
  • 扩展运算符+结构赋值
let [head, ...tail] = [1, 2, 3, 4];
  • 不完全解构
let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
  • 解构赋值必须为可遍历解构,即具有iterator接口

如果等号的右边不是数组(或者严格地说,不是可遍历的结构,参见《Iterator》一章),那么将会报错。

另外一方面,居于iterator接口的解构都可以使用结构赋值,Set和Map,甚至generator

let [x, y, z] = new Set(['a', 'b', 'c']);
x // "a"
function* fibs() {
  let a = 0;
  let b = 1;
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}

let [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5
  • 结构赋值+默认值

ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。

let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
let [x = 1] = [null]; x // null

这里即便是null, null和undefined在‘==‘的情况下是相等的,但是不全等,所以上面代码x最后的值是null,而不是默认值1

如果默认值是函数表达式或者就是函数,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。


对象的结构赋值

  • 对象的结构赋值等式右边也要是对象
    由于解构赋值要求等号右边是一个对象,所以如果等号右边是undefined或null,就会报错,因为它们无法转为对象
let { x, y, ...z } = null; // 运行时错误
let { x, y, ...z } = undefined; // 运行时错误
  • 解构赋值必须是最后一个参数,否则会报错。
let { ...x, y, z } = someObject; // 句法错误
let { x, ...y, ...z } = someObject; // 句法错误
  • 对象的结构赋值是按属性名赋值的,与数组结构赋值不同,它与顺序无关
//说明对象解构赋值与顺序无关
let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
  • 对象解构赋值内部机制,模式
    对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量,如果没找到则为undefined
let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };

上面代码左边的foo:foo,第一个foo是模式,第二个foo才是被赋值的变量

  • 嵌套赋值
let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};

let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"

这里的p是模式,不是变量,因此不会被赋值。如果p也要作为变量赋值,可以写成下面这样。

let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};

let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]

如果解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错。

  • 对象结构赋值+默认值
  • 已经声明的变量用于解构赋值
//错误写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error

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

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

字符串的结构赋值

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

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

函数参数结构赋值

  • 参数结构赋值的默认值
    第一种写法
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]

等式左边部分{x = 0, y = 0}这一块是默认值部分,中间的等号+右边的{}才是解构赋值部分并且还是传入参数部分,右边的{}也是默认值部分,默认传入参数为{}
这里逻辑有点复杂,我要好好解释一下

  • move({x = 0, y = 0} = {})这部分使用了两次默认值,一次解构赋值
  • 先说这个默认赋值{x = 0, y = 0} = {},如果外界调用参数的时候什么参数都没有传,那么参数默认使用{}(右边的{}),所以此时入参为默认是空对象
  • 然后是第二次默认赋值,入参为空对象,赋值给左边的{x = 0, y = 0},之前写到过,如果默认赋值右边为严格的undefined,才会使用默认值,这符合条件,所以x,y为0,0

第二种写法

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]

看懂第一种写法之后,第二种写法就明白什么回事了,第二种写法只使用了一次默认值,即等号右边的{ x: 0, y: 0 },给传入参数默认赋值0,0,所以代码里面当我们传入参数为{x:3}的时候,因为有传参并且不为undefined,所以x得到了值3,而y没有值,所以是undefined。

解构赋值用途

  • 交换变量的值
let x = 1;
let y = 2;

[x, y] = [y, x];
  • 从函数返回多个值
// 返回一个数组

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

// 返回一个对象

function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();
  • 无序给函数传参
// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);

// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
  • 提取 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]
  • for…of…
for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// 获取键名
for (let [key] of map) {
  // ...
}

// 获取键值
for (let [,value] of map) {
  // ...
}
  • require 模块时候
const { SourceMapConsumer, SourceNode } = require("source-map");
  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值