ES6变量的解构赋值

·  阅读 107

1. 数组的解构赋值

在ES5中,为变量赋值必须采用直接赋值的形式

var foo = 'abc'
var bar = 123
复制代码

利用ES6的解构赋值,可以简化为

let [foo, bar] = ['abc', 123]
复制代码

上面的代码表示,声明foo和bar两个变量,并且按照两边数组中的顺序一一初始化值,实际上解构赋值的写法属于一种“模式匹配”,这种“模式匹配”还可以用于更复杂的数据解构中。

let [foo, [[bar, baz], qux]] = ['147', [['258', '369'], 'abc']]
foo // '147'    bar // '258'
baz // '369'    qux // 'abc'

let [, , foo] = ['147', '258', '369']
foo // '369'

const [foo, bar, ..., qux ] = ['a', 'b', 'c', 'd', 'e'];
foo // 'a'
bar // 'b'
qux // 'e'

let [foo, [bar, ...baz]] = ['a', ['b', 'c', 'd', 'e']]
foo // 'a'
bar // 'b'
baz // ['c', 'd', 'e']

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []

复制代码

如果赋值方无法满足被赋值方的结构, 则部分变量解构不成功,解构不成功的变量等于undefined, 以下情况baz解构不成功, 值为undefined。赋值方的值,有且只有undefined无法使解构赋值失败/默认值生效

var [baz] = [];
var [qux, baz] = [1];
复制代码

如果赋值方能满足被赋值方的结构, 而且还有多余,则能匹配的部分就解构成功

let [foo, [bar], qux] = [1, [2, 3], 4]
foo // 1
bar // 2
qux // 4
复制代码

如果赋值方是不可遍历的结构, 则解构会报错

// 报错
let [qux] = 1;
let [qux] = false;
let [qux] = undefined;
复制代码

对于Set结构,也可以使用数组的解构赋值。

let [x, y, z] = new Set(["a", "b", "c"]);
x // "a"
复制代码

事实上,只要某种数据结构具有Iterator接口,都可以采用数组形式的解构赋值。 下面的代码中fibs是一个Generator函数,原生带有iterator接口, 解构赋值依次从iterator 接口取值

function* fibs() {
  var a = 0;
  var b = 1;
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}

var [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5
复制代码

解构赋值允许指定默认值

[x, y = 'b'] = ['a']; // x='a', y='b'
[x, y = 'b'] = ['a', null]; // x='a', y=null
[x, y = 'b'] = ['a', undefined]; // x='a', y='b'
复制代码

如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。下面代码中,因为x能取到值,所以函数f根本不会执行。

function f() {
  console.log('aaa');
}

let [x = f()] = [1];
复制代码

默认值可以引用解构赋值的其他变量,但该变量必须已经声明。

let [x = 1, y = x] = [2];    // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = [];     // ReferenceError
复制代码

2. 对象的解构赋值

简单的对象解构赋值:

const { foo, bar } = { foo: "a", bar: "b" };
foo // "a"
bar // "b"
复制代码

数组的解构赋值是依据按数组元素的顺序依次解构的,不同的是,对象的解构赋值对属性的顺序没有要求,而是需要属性名相对应才能成功解构赋值。

const { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

const { qux } = { foo: "aaa", bar: "bbb" };
qux // undefined
复制代码

上面的第二个例子,在赋值方找不到属性名qux,被赋值方的取不到值,为undefined

如果变量名与属性名不一致,必须写成下面这样。

let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'
复制代码

回顾对象解构赋值的第一个例子,其写法实际是以下写法的简写。

const {foo: foo, bar: bar} = {foo: "a", bar: "b"}
复制代码

下面的代码中,先用let声明变量,再在解构赋值中参与赋值,注意行首的圆括号是必须的,因为以大括号起首的语句会被执行器认为是匿名代码块,而不是解构赋值,所以需要用圆括号表示其意义

let foo;
({foo} = {foo: 1}); // 成功

let baz;
{bar: baz} = {bar: 1}; // 报错
复制代码

解构赋值用于对象和数组嵌套的解构, 注意k和p是属性名,只有a和b才是被赋值的变量

const foo = {
    k: [
        '123',
        {
            p: '456'
        }
    ]
}
const {k: [a, {p: b}]} = foo;
a // '123'
b  // '456'
k // error: k is undefined
p // error: p is undefined
复制代码

把被赋值方的值解构赋值到对象/数组中

const o = {}, a = [];
({name: o.name, age: a[0]} = {name: 'Miku', age: 10})

o // {name: 'Miku'}
a // [10]
复制代码

对象的解构赋值也可以指定默认值

var {x = 3} = {};
x // 3

var {x, y = 5} = {x: 1};
x // 1
y // 5
复制代码

和数组的解构赋值一样,被赋值方有且只有undefined可以使解构赋值失败/默认值生效

var {x = 3} = {x: undefined};
x // 3

var {x = 3} = {x: null};
x // null
复制代码

对象的解构赋值,可以很方便地将现有对象的值(包括简单类型,引用类型,函数等),赋值到某个变量。

const {promise1, promise2} = fn()
Promise.all(promise1, promise2).then(...)
复制代码

3. 函数参数的解构赋值

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

function add([x, y]){
  return x + y;
}

add([1, 2]); // 3
复制代码

函数参数的解构也可以使用默认值。

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]
复制代码

和对象的解构赋值一样,函数参数的赋值方有且只有undefined能使解构失败/默认值生效

[1, undefined, 3].map((x = 'yes') => x);
// [ 1, 'yes', 3 ]
复制代码

4. 其他类型的解构赋值

解构赋值的规则是,只要赋值方的值不是对象,就先将其转为对象。

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

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

类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。

let {length : len} = 'hello';
len // 5
复制代码

数值和布尔值解构赋值时,会先转为对象。

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

let {toString: s} = true;
s === Boolean.prototype.toString // true
复制代码

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

let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
复制代码

5. 应用场景

交换变量的值,不再需要创建中间值

[foo, bar] = [bar, foo];
复制代码

分别获取函数返回的多个值

function fn () {
    return {foo: '123', bar: '234'}
}
const {foo, bar} = fn()
复制代码

函数接收参数时直接解构

function fn ({foo, bar, qux}) {
    return `${foo} ${bar} ${qux}!`
}
const param = {
    foo: 'Welcome',
    bar: 'to',
    qux: 'javascript'
}
console.log(fn(param))
//Welcome to javascript!
复制代码

提取json中的值作为变量

const person = {
    name: 'Miku',
    age: 1,
    birth: '1996-2-18'
}
let {name, age, birth} = person;
console.log(name, age, birth)
//Miku 1 1996-2-18
复制代码

遍历ES6 Map解构, 如果只想把key赋值给变量, 可以写成[key], 如果指向把value赋值给变量,则写[, value]

const areas = new Map()
areas.set('浙江省', '杭州市')
areas.set('广东省', '广州市')

for (let [key, value] of areas) {
  console.log(`${key}-${value}`);
}
//浙江省-杭州市
//广东省-广州市
复制代码

node module.exports/require函数和ES6 export/import

//node module.exports/require
const person = {name: 'Miku', age: 1}
const student = {grade: 3, class: 2}
module.exports = {person, student}
const {person} = require('......')
console.log(person)
//{name: 'Miku', age: 1}

//ES6 export/import
export const fnCollect = {
    fn1 () {
        return 'this is fn1'
    },
    fn2 () {
        return 'this is fn2'
    }
}
//import
import {fn1} from '......'
console.log(fn1())
//this is fn1
复制代码
分类:
阅读
标签:
分类:
阅读
标签:
收藏成功!
已添加到「」, 点击更改