数组的解构赋值
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); //4
let [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);