ES6新语法之---解构(4)
ES6中引入了新语法--解构,我们把这个功能看做是结构化赋值,会更容易理解些。
第一部分:ES5数组、对象结构
1.1:数组结构
function foo() { return [1, 2, 3] } var tmp = foo(), a = tmp[0], b = tmp[1], c = tmp[2]; console.log(a, b, c)
我们构造了一个手动赋值,把foo()返回数组中的值赋给独立变量a、b和c,为了实现这一点我们需要一个临时变量tmp。
1.2:对象结构
function foo() { return { x: 4, y: 5, z: 6 } } var tmp = foo(), a = tmp.x, b = tmp.y, c = tmp.z; console.log(a, b, c)
这里实现对象的赋值,依然使用了临时变量tmp。
ES6为解构新增了一个专门语法,专用于数组解构和对象解构,消除了前面实现解构中的临时变量tmp,使代码更简洁。
第二部分:ES6解构
2.1:数组、对象解构
function foo() { return [1, 2, 3] } function bar() { return { x: 4, y: 5, z: 6 } } var [a, b, c] = foo(); var {x: x, y: y, z: z} = foo() console.log(a, b, c) console.log(x, y, z)
左侧的[a, b, c]和{x: x, y: y, z: z}更像一种数据组成结构,把右边的数据按照左边的结构赋值到对应的变量中。
2.2:结构中当属性名和要赋的变量名相同的时候,可以简写
function bar() { return { x: 4, y: 5, z: 6 } } var {x, y, z} = bar() //这里我们可简写 console.log(x, y, z)
那么这里具体是省略了属性'x:',还是省略了赋值部分':x',其实这里省略了属性部分'x:'。
但并不是说有了简化方式,之前的冗长形式就无用了,它支持把属性赋给非同名变量。
function bar() { return { x: 4, y: 5, z: 6 } } var {x: bam, y: baz, z: bap} = bar() console.log(bam, baz, bap) //这里讲bar()结果中的x,y,z分别赋给了bam, baz, bap。 console.log(x, y, z) //ReferenceError: x is not defined
2.3不仅仅用于声明
上例中都是在var(let/const)声明中使用了解构赋值,但其赋值解构是一个通用的赋值操作,不只是应用在声明中。
function foo() { return [1, 2, 3] } function bar() { return { x: 4, y: 5, z: 6 } } var a, b, c, x, y, z [a, b, c] = foo(); //我们直接可以使用解构进行赋值操作。 ({x, y, z} = bar()); //如果没有()那么{}会被识别成代码块而非对象。 console.log(a, b, c); console.log(x, y, z);
赋值表达式并不必须是变量标识符。任何合法的赋值表达式都可以
var o = {}; [o.a, o.b, o.c] = foo(); //这里可以是o的属性,并不必须是声明的变量名。 ({x: o.x, y: o.y, z: o.z} = bar()); console.log(o.a, o.b, o.c) console.log(o.x, o.y, o.z)
或者使用计算出的属性表达式:
var which = 'x', o = {}; ({[which]: o[which]} = bar()) //[which]是计算出的属性,结果是x console.log(o.x)
可以使用一般的赋值创建对象映射:
//对象映射为对象 var o1 = {a: 1, b: 2, c:3}, o2 = {}; ({a: o2.x, b: o2.y, c: o2.z} = o1) console.log(o2.x, o2.y, o2.z); //1, 2, 3 //对象映射为数组 var o1 = {a: 1, b: 2, c:3}, a2 = []; ({a: a2[0], b: a2[1], c: a2[2]} = o1) console.log(a2); //[1, 2, 3] //数组映射为对象 var a1 = [1, 2, 3], o2 = {}; [o2.a, o2.b, o2.c] = a1; console.log(o2) //{a: 1, b: 2, c: 3}
//数组重排序到另一个
不使用临时变量,完成两个变量值交换的问题。
var x = 10, y = 20; [y, x] = [x, y] console.log(x, y) //20, 10
2.4重复赋值
2.4.1对象解构允许多次列出同一个源属性:
var {a: x, a: y} = {a: 1} console.log(x, y) // 1, 1 var {a: {x: X, x: Y}} = {a: {x: 1}} //这里我们不仅能得到a本身的值,还能得到a中子对象属性x的值。 console.log(X, Y); // {x: 1} , 1, 1 ({a: X, a: Y, a: [z]} = {a: [1]}); X.push(2) Y[0] = 10; console.log(X, Y, z) //[10, 2] , [10,2] 1
2.4.2解构赋值表达式
对象或数组解构的复制表达式的完成值是所有右侧对象/数组的值。
//对象的解构赋值表达式 var o = {a: 1, b: 2, c: 3}, a, b, c, p; p = {a, b, c} = o; // {a, b, c} = o;完成值是o, 那么p就是o一份拷贝 console.log(a, b, c); // 1, 2, 3 console.log(p === o); //true //数组的解构赋值表达式 var o1 = [1, 2, 3], a1, b1, c1, p1; p1 = [a1, b1, c1] = o1; // {a1, b1, c1} = o1;完成值是o1, 那么p1就是o1一份拷贝 console.log(a1, b1, c1); // 1, 2, 3 console.log(p1 === o1); //true
通过持有对象/数组的值作为完成值,可以把解构赋值表达式组成链。
var o = {a: 1, b: 2, c: 3}, p = [4, 5, 6], a, b, c, x, y, z; ({a} = {b, c} = o); // {b, c} = o的结果依旧是对象o,继续使用{a} = o,这样就组成链 [x, y] = [z] = p; console.log(a, b, c) console.log(x, y, z)
2.5数组/对象中部分值赋值解构
2.5.1只赋值结构部分值。
var [, b] = foo(); //返回的1,2丢掉了 var {x, z} = bar(); //返回的5丢掉 console.log(b, x, z);
为比分解出来的更多值赋值
//foo()和bar()的方法在前面已经提到,不再重复
var [, ,c, d] = foo(); var {w, z} = bar(); console.log(c, z); // 3, 6 console.log(d, w); // 多余的值会被赋值为:undefined, undefined
2.5.2 默认值赋值
与默认函数参数值类似,结构也可以提供一个用来赋值的默认值。
var [a = 3, b = 6, c = 9, d = 12] = foo(); var {x = 5, y = 10, z = 15, w = 20} = bar(); console.log(a, b, c, d); //1, 2, 3, 12,其中foo()返回值没有d就是用默认值。 console.log(x, y, z, w); // 4, 5, 6, 20 ,w一样 //赋值表达式 var {x, y, z, w: W = 20} = bar(); console.log(x, y, z, WW)
2.5.3 解构参数
1>函数参数为数组/对象的解构
//参数为数组的解构赋值 function foo([x, y]) { console.log(x, y) } foo([1, 2]); // 1, 2 foo([1]); // 1, undefined foo([]); // undefined, undefined //参数为对象的解构赋值 function foo({x, y}) { console.log(x, y) } foo({y: 1, x: 2}); // 2, 1 foo({y: 2}); // undefined, 2 foo({}); // undefined, undefined
2>解构默认值和函数默认值
function fun({x = 10} = {}, {y} = {y: 10} ) { console.log(x, y) } fun(); //10, 10 fun({}, {}) //10, undefined
这里输出的结果是否和期望的一样呢?那么结果为什么是这样呢?
理解:{y} = {y : 10},这种情况如果第一个参数省略或者传入undefined,就会使用{y : 10}默认对象。
而对于{x = 10} = {},其中的{x = 10}类似解构默认值,如果第一个参数省略或者传入undefined,就会使用{}对象,接着{}会按照{x = 10}的结构进行解构,没有传入任何值就用x的默认值10。
总结:结构为我们开发带了很多便利,但并不是说应该肆无忌惮的使用,而是应该在合适的场景使用,这样才能真正提高我们的开发效率。