目录
ES6 允许按照一定模式从数组和对象中提取值后对变量进行赋值,这被方式称为解构(解析结构的意思)。
数组的解构赋值
注意点
1、赋值等号的左右侧的数组结构需要一致,这个叫做”模式匹配”
let [a,b,c] = [1,2,3]; console.log(a,b,c); // 结果:1 2 3 let [a1,[a2,a3]] = [11,[22,33]]; console.log(a1,a2,a3); // 结果:11 22 33
2、如果左右两侧的变量数与数值数的数量不匹配, 那么就直接跳过缺失部分( 左边的跳过了, 右侧相应位置的也要跳过)
let [,,td] = ['n','p','m']; console.log(td); // 结果:m let [x,,z] = [24,25,26]; console.log(x,z); // 结果:24 26
3、如果左侧某个变量前有三个小点, 那么意味着右侧对应位置及以后的所有数值将组合成一个数组,赋值给左侧的该变量,且左侧必须是最后一个变量才可以在前面加三个小点,否则报错
let [start,...end] = [1,2,3,4,5]; console.log(start,end); // 结果:start 1 ;end [2, 3, 4, 5] let [x1,y1,y2,...z1] = ['hello']; console.log(x1,y1,y2,z1); // 结果:hello undefined undefined [] // let [x2,x3,...x4,x5] = ['h','e','l','l','o']; // 报错:Uncaught SyntaxError: Rest element must be last element
解析不成功与不完全解析
解析不成功
当等号左边的变量比等号右边的值多的时候就会解析不成功,对应的变量的值就等于undefined。
let [x1,y1,y2,...z1] = ['hello']; console.log(x1,y1,y2,z1); // 结果:hello undefined undefined [] let [p1,p2] = [1]; console.log(p1,p2); // 结果:1 undefined
不完全解析
等号左边的模式,只匹配一部分的等号右边的数组
let [a, [b],c] = [1,[2,3,4],5]; console.log(a,b,c); // 结果:1 2 5
解析赋值要求
赋值(等号的右边)必须是可遍历的结构,否则将会报错。
// 报错 let [foo] = 1; let [foo] = false; let [foo] = NaN; let [foo] = undefined; let [foo] = null; let [foo] = {};
指定默认值
解构赋值允许指定默认值。注意,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当右侧一个数组成员严格等于undefined,默认值才会生效。 (因为要是采用==,那么就会产生数据类型转换了)
console.log(c1,c2,c3); // 结果:12 undefined 3 let [d1='12',d2] = [1,4]; console.log(d1,d2); // 结果:1 4
注意1:如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined
let [e1 = 66] = [undefined]; console.log(e1); // 结果:66 let [e2 = 66] = [null]; console.log(e2); // 结果:null let [e3 = 66] = [NaN]; console.log(e3); // 结果:NaN
注意2:默认值可以引用解构赋值的其他变量,但该变量必须已经声明。
let [g1 = 7, g2 = g1] = []; console.log(g1,g2); // 结果:7 7 let [g3 = 7, g4 = g3] = [4,5]; console.log(g3,g4); // 结果:4 5 let [g5 = 7, g6 = g5] = [3]; console.log(g5,g6); // 结果:3 3 let [g7 = g8, g8 = 7] = []; // 报错:Uncaught ReferenceError: Cannot access 'g8' before initialization
惰性求值
如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。
function fc() { console.log('惰性求值'); } let [f1 = fc()] = 'hehe'; console.log(f1); // 结果:h let [f2 = fc()] = ''; // 结果调用fc函数:惰性求值
对象的解构赋值
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
示例
例1:等号左边的两个变量的次序,与等号右边两个同名属性的次序不一致,但是对取值完全没有影响
let {a1,a2} = {a1:'1',a2:'2'}; console.log(a2,a1); // 结果:2 1
例2:变量没有对应的同名属性,导致取不到值,最后等于undefined
let {b1} = {b2:'3',b3:4}; console.log(b1); // 结果:undefined
例3:对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者,前者是匹配模式,后面的才是变量,使用的时候取后面的变量,否则报错。
let {c2:cn} = {c2:'3',c3:4}; console.log(cn); // 结果:3 // console.log(c2); // 结果:Uncaught ReferenceError: c2 is not defined
例4:对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量
let {log} = console; log('呵呵呵!') // 结果: 呵呵呵! let {cos,sin,log,tanh}=Math; console.log(tanh(45)); // 结果:1
例5:由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构
let o = [1,3,5,7,9]; let {0:first,[o.length-1]:last} = o; console.log(first,last); // 结果:1 9
例6:如果要将一个已经声明的变量用于解构赋值,必须非常小心。左侧代码的写法会报错,因为 JavaScript 引擎会将{x}理解成一个代码块(最简单的块级作用域),从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。
嵌套
与数组一样,解构也可以用于嵌套结构的对象。注意,:前面的是匹配模式,而不是变量,如celebrity1和celebrity2,因此不会被赋值。[]数组变量可以是自定义,{}匹配的变量必须和对象值中的一致。
let obj = { celebrity1:{ name1:'墨子' }, celebrity2:[ {name2:'荀子',era:'战国'} ] } let {celebrity1,celebrity1:{name1},celebrity2:[{name2,era}]} = obj; console.log(celebrity1,name1,name2,era); // 结果:{name1: "墨子"} "墨子" "荀子" "战国"
字符串的解构赋值
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。 类似数组的对象都有一个length属性,因此还可以对这个属性解构赋
let a = '1234567890'; let {length:len} = a; console.log(len); // 结果:10 let [b1,b2,b3,b4,b5] = a; console.log(b1,b4); // 结果:1 4
数值和布尔值的解构赋值
解构赋值的规则是:只要等号右边的值不是对象或数组,就先将其转为对象。 由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。
let {p1 : x} = true; console.log(x); // 结果:undefined let {p2 : y} = null; // 报错:Uncaught TypeError: Cannot destructure property 'p2' of 'null' as it is null. let {p3 : z} = undefined; // 报错:Uncaught TypeError: Cannot destructure property 'p3' of 'undefined' as it is undefined.
函数参数的解构赋值
函数参数的解构也可以使用默认值。
这里有两个步骤:
1、对函数里面的参数进行解构赋值, 得到的结果就是{x=0,y=0}
2、函数调用时进行数据传参, 如果传入的参数可以正常进行解构赋值,那么就使用传进的参数否则,就调用默认值
左侧代码是为函数move的参数指定默认值,而不是为变量x和y指定默认值,所以会得到与前一种写法不同的结果。所以函数的默认参数是{x=0,y=0},一旦这个函数在执行时传入了其他参数, 那么这个默认的参数就不起作用,只有当函数在执行不传入任何参数, 这个默认参数才有作用
解构赋值的常见应用场景
变量交换
// 新方法:解构赋值
let x = 1;
let y = 2;
[x,y] = [y,x];
console.log(x,y);
// 1、用一个中间变量
let z = x;
x = y;
y = z;
console.log(x,y);
// 2、异或
x = x^y;
y = x^y;
x = x^y;
console.log(x,y);
// 3、算术运算符 - +
x = x + y;
y = x - y;
x = x - y
console.log(x,y);
从函数返回多个值
function fn() {
return [1, 2, 3];
}
// let [a, b, c] = fn();
// console.log(b); // 结果:2
let c = fn();
let a = c[0];
let b = c[1];
let d = c[2];
console.log(c); // 结果:[1, 2, 3]
console.log(a); // 结果:1
console.log(b); // 结果:2
console.log(d); // 结果:3
函数参数的定义
解构赋值可以方便地将一组参数与变量名对应起来