ES6解构赋值

来源:互联网 发布:防水运动鞋 知乎 编辑:程序博客网 时间:2024/06/04 19:29

数组的解构赋值

ES6中允许按照一定的模式,从数组和对象中提取值,对变量进行赋值,这称为解构赋值,在ES5中为变量赋值,只能直接指定值

首先,有几个简单的例子

1)左边和右边“模式匹配”,完全解构,按照对应的位置,为变量赋值

let [a, b, c] = [1, 2, 3];console.log(a, b, c);  //1 2 3//略微复杂一点的嵌套,但是也是模式匹配的let [foo, [[bar], baz]] = [1, [[2], 3]];console.log(foo, bar, baz);  //1 2 3

babel编译后的代码

"use strict";var a = 1;var b = 2;var c = 3;console.log(a, b, c); //1 2 3

发现“模式匹配”的情况下,编译出的代码就是单个定义的

2)左边和右边“非模式匹配”,部分解构

let [,,third] = [3, 5, 7];console.log(third);  //7//和扩展运算符一同使用let [head, ...tail] = [1, 2, 3, 4];console.log(head, tail);// 1  [2, 3, 4]let [x, y, ...z] = [1];console.log(x, y, z);// 1 undefined []

解构不成功,变量的就等于undefined,因为有扩展运算符,所以z的值为空数组

bable后的代码

第一段的话,就是定义了个数组,赋值为右边的值,然后,给指定变量赋予指定的值

"use strict";var _ref = [3, 5, 7];var third = _ref[2];console.log(third); //7

第二段的话,是含有扩展运算符的,就是单独定义

"use strict";var head = 1;var tail = [2, 3, 4];console.log(head, tail);

第三段的话,可以看作是前面两个的综合

"use strict";var _ref = [1];var x = _ref[0];var y = _ref[1];var z = _ref.slice(2);console.log(x, y, z); // 1 undefined []

需要注意的地方:如果等号右边的不是数组(不是可遍历的结构)就会报错,当然只要转为带有Iterator接口的对象就好了

let [re] = 1;
let [x, y, z] = new Set([1, 2, 4]);

3)默认值的情况

let [x = 1] = [];console.log(x);  // 1

当默认值和右边同时有值的话,那么取的是等号右边的[]中的值

let [y, z = 2] = [3, 4];console.log(z); //4let [r = 99] = [null];console.log(r);  //null

当为undefined的时候取得就是默认值

let [r = 99] = [undefined];console.log(r);

对象的解构赋值

1)简单的情况

let {foo, bar} = {bar: 'aaa', foo: 'bbb'};console.log(foo, bar);// bbb  aaa

对象的属性是没有次序的,变量必须和属性同名,才能取得到正确的值,babel后的代码如下

'use strict';var _bar$foo = { bar: 'aaa', foo: 'bbb' };var foo = _bar$foo.foo;var bar = _bar$foo.bar;console.log(foo, bar); // bbb  aaa

当没有同名属性的时候,就等于undefined

let {brr} = {bar : 999};console.log(brr); // undefined

对象赋值的机制是,先找到同名属性,然后再赋给对应的变量,真正被赋值的是后者,而不是前者

let {foo: bar} = {bar: 'aaa', foo: 'bbb'};console.log( bar); // bbb

前面的代码可以看做是下面的简写方式

let {foo:foo, bar:bar} = {bar: 'aaa', foo: 'bbb'};console.log( bar); //aaa

2)多层嵌套的方式

let obj = {    p: [        'hello',        {y : 'world'}    ]};let {p, p: [x, {y}]} = obj;console.log(p, x, y);  //[ 'hello', { y: 'world' } ]  'hello'  'world'

这段代码,建议通过自己的理解,写出等号左边的部分,如果写出来了,就说明对于对象和数组的结构赋值有了比较清晰的认识,数组的左边定义变量的形式是[],对象的左边定义变量的形式是{}

const node = {    loc: {        start : {            line: 1,            column: 5        }    }};let {loc, loc: {start : {line, column}}} = node;console.log(loc, line, column);// { start: { line: 1, column: 5 } }  1  5

3)默认值的情况,和数组的是类似的,这里就不在赘述

4)已经声明的变量用于解构赋值的情况

//会出现错误,js引擎会将{x}理解为一个代码块,从而发生了语法错误let x;{x} = {x: 1};

正确的写法,需要加一对括号

let x;({x} = {x: 1});

babel后的代码

"use strict";var x = undefined;var _x = { x: 1 };x = _x.x;_x;

5)几个特殊的用法

将现有对象的方法,赋值给某个变量

let {sin, cos, tan} = Math;

数组也可以进行对象属性的解构

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

字符串的解构赋值

const [a, b, c, d, e] = "hello";console.log(a, b, c, d, e);// h e l l o

函数参数的结构赋值

1)不含默认值

function add([x, y]) {    return x + y;}var res = add([1, 2]);console.log(res);// 3

babel后的结果

"use strict";var _slicedToArray = (function () {    function sliceIterator(arr, i) {        var _arr = [];        var _n = true;        var _d = false;        var _e = undefined;        try {            for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _                arr.push(_s.value);                if (i && _arr.length === i)                    break;            }        } catch (err) {            _d = true; _e = err;        } finally {            try {                if (!_n && _i["return"])                    _i["return"]();            } finally {                if (_d)                    throw _e;            }         }         return _arr;    }    return function (arr, i) {        if (Array.isArray(arr)) {            return arr;        } else if (Symbol.iterator in Object(arr)) {            return sliceIterator(arr, i);        } else {            throw new TypeError("Invalid attempt to destructure non-iterable instance");        } };    })();function add(_ref) {    var _ref2 = _slicedToArray(_ref, 2);    var x = _ref2[0];    var y = _ref2[1];    return x + y;}var res = add([1, 2]);console.log(res);

大概看了一下_slicedToArray这个函数,感觉它的作用就是产生真的数组

[[1, 2], [3, 4]].map(([a, b]) => {    console.log(a + b);});// 3, 7

2)包含默认值的情况

为变量x和y指定默认值,函数的参数是一个对象,通过对这个对象进行解构,得到变量x和y的值,解构失败的情况下,x和y等于默认值

function move({x=0, y=0} = {}) {    return [x, y];}var res = move({x: 3, y: 4});console.log(res); //[3, 4]console.log(move());// [0, 0]console.log(move({}));// [0, 0]

为函数参数指定默认值

function move({x, y} = {x: 1, y : 2}) {    return [x, y];}var res = move({x: 3, y: 4});console.log(res); //[ 3, 4 ]console.log(move());// [ 1, 2 ]console.log(move({}));// [ undefined, undefined ]

undefined可以触发函数的默认值

[1, undefined, 3].map((x= 88) => console.log(x));  // 1 88 3

用途

1)交换两个变量的值

let x = 1;let y = 2;[x, y] = [y, x];console.log(x, y); // 2 1

2)从函数中返回多个值

//返回数组function example() {    return [3, 4, 5];}let [a, b, c] = example();console.log(a, b, c);
//返回对象function test() {    return {        foo : 1,        bar : 2    };}let {foo, bar} = test();console.log(foo, bar);