数组的解构赋值
常用的变量赋值,我们是直接使用以下的方法进行赋值。
let x = 1;
let y = 'two';
let z = false;
在ES6中,允许使用以下方法进行变量的赋值。
let [x,y,z] = [1,'two',false]
console.log(x,y,z) // 1 two false
从数组中提取每个位置的值,按照位置对应的顺序去赋值。
下面举一些例子,大概便可以更加直观的发现他的匹配规则:
let [a,b,[c,d]] = ['A','B',['C','D']];
console.log(a,b,c,d) // A B C D
let [a,b,c] = ['A','B',['C','D']];
console.log(a,b,c) // A B ["C", "D"]
let [,,c] = ['A','B','C']
console.log(c) // C
let [,first,...more] = ['A','B','C','D']
console.log(first,more) // B ['C','D'] ... 拓展符号,不懂可以百度
以上我们对于等号两边数组的 ” 模板 “ 来看是完全匹配的。那么对于匹配规则不是那么完整的,会出现什么结果。
let [first,second] = [1]
console.log(first,second) //1 undefined
可以看到的是,当等号两边的数组相对的位置没有匹配上的时候,就会出现解构失败,没有匹配上的变量会等于undefined。可以观察到的是这时候,等号右侧的数组的长度是小于左边的长度。
那么就会有另外一种情况是等号左侧的长度大于右侧的长度。
let [a,b,c] = ['A','B','C','D']
console.log(a,b,c) // A B C
这种情况呢,ES6称之为不完全解构。其实我的理解是,反正是右边根据位置去赋值给左边的变量,也就是左边实际来说是处于被动的位置,并不清楚右边的数组内部。那么这种不完全赋值,其实和完全解构没什么区别。在实际开发中,我们更多遇到是不完全解构。暂时不要去考虑两边的类型不同的情况,往后看你就自己可以推出来了
日常开发我们会遇到这种情况,如果被解构的数组为空,那么我们的变量岂不是都为undefined了?针对这种情况,我们可以去设置变量的默认值。如下例子:
let [a] = [];
console.log(a) // undefined
let [a = 'A0'] = []
console.log(a) // A0
let [a = 'A0'] = ['A1']
console.log(a) // A1
这里要注意ES6中使用严格相等运算符,判断一个位置是否有值,所以只有当一个数组元素严格等于undefined,默认值才会生效。
let [x = 'X'] = [null]
console.log(x) // null
let [x = 'X'] = [undefined]
console.log(x) // X
对象的赋值解构
对象的解构和数组的解构存在一个很重要的不同,当然这个不同也是因为数组和对象的结构类型不同有关,数组是有序的,而对象是无序的。所以在对象解构赋值的时候并不是通过位置来对应赋值,而是通过对象特有的key-value的特性,key的唯一性来赋值。所以的他的匹配规则,就是变量和属性名key一致来进行赋值。解构失败的话,也是undefined。
let {first,second} = {second:'老二',first:'老大',boss:'老板'}
console.log(first,second) // 老大 老二
let {third} = {second:'老二',first:'老大',boss:'老板'}
console.log(third) // undefined
那么对象中的方法呢?其实方法都是继承Function类型的,我们把它和数组一样对待就行。下面举几个对象中方法解构赋值的例子:
let {log,warn,info} = console;
log('1111');
warn('warning');
那么如果我们想要想要把对象中的属性通过解构赋值到自定义的变量上呢?我们可以通过类似起别名的方式去匹配对应关系,然后赋值到自定义的变量上面。
let {abs:myAbs,floor:myFloor,random:myRandom} = Math;
myAbs(-1) // 1
myFloor(2.369) // 2
myRandom() // 0.5500440022808113
这里冒号前面是Math对象里面的属性,我们称它为匹配模式,冒号后面的是要赋值自定义变量。
再举一个例子加深一下匹配模式:
let obj = {
x:[
'X',
['Y'],
{z:['这里是z的数组']}
]
}
let {x:[x1,[y],{z}]} = obj
console.log(x1) // X
console.log(y) // Y
console.log(z) // ["这里是z的数组"]
注意了,解构是可以取到继承的属性和方法的。
let dad = {name:'father'}
let mam = {skill:'打儿子'}
Object.setPrototypeOf(dad,mam);
let {skill} = dad
console.log(skill) // 打儿子
当然了,对象的解构也是可以设置默认值的。默认值生效的条件还是对象的属性值严格等于undefined。
let { x:myX = 10 } = {}
console.log(myX) // 10
let { x:myY = 20 } = { x : 100 }
console.log(myY) // 100
对象的解构赋值还有一些杂项需要注意一下。
- 对于已经声明好的变量进行解构赋值
let a;
({a} = {a:'A'})
- 解构赋值允许等号左侧为空,但是他是不会报错得。
- 数组可以进行对象解构,对应关系的话,将对象的属性名换成位置的数值对应变量名。
字符串的解构
字符串的解构赋值,是因为字符串可以被转换成一个类似数组的对象。字符串的长度可以使用length来获取。所以也可以去解构他。
let str = 'abcdef'
console.log(str.split('')) // [a,b,c,d,e,f]
let [a,b,c,d,e] = 'ABCDE'
console.log(a,b,c,d,e) // A B C D E
let {length:len} = 'ABCDE'
console.log(len) // 5
数值和布尔值的解构赋值
在解构赋值的时候,如果等号右侧为数值或者布尔值时,会先转换为对象。
解构赋值的规则是,只要等号右侧的值不是对象或者数组,就将其先转为对象。但是undefined和null是无法转化为对象的,所以无法进行解构赋值,会爆错误。
let {toString:toS} = 123
console.log(toS) // toString() { [native code] }
toS = Number.prototype.toString // true
let {toString:toT} = true
toT = Boolean.prototype.toString // true
函数参数的解构赋值
首先先看一个例子:
function fn([a,b]){
console.log(a,b)
}
fn(['A','B']); // A B
函数参数是一个数组,但是在传入的时候,参数其实已经被解构为变量a和b,函数使用的时候,使用的其实就是a和b。淡然函数的解构也可以使用默认值。
function fn1({x=1,y=2}={}){
console.log(x,y)
}
fn1() // 1 2
fn1({x:'X',y:'Y'}) // X Y
fn1({}) // 1 2
fn1({x:'X1'}) // X1
// 换个写法来看一下
function fn2({x,y}={x:'X',y:'Y'}){
console.log(x,y)
}
fn2() // X Y
fn2({}) // undefined undefined
fn2({x:3}) // 3 undefined
fn2({x:3,y:4}) // 3 4
fn1的参数是一个对象,对传入的参数进行解构然后去为变量x和y赋值,而变量x和y是拥有默认值的。fn2以一个对象为默认值,而不是为变量x和y设置默认值,所以x和y会出现undefined的情况。
开发中解构的使用
- 交换变量
let a = 'a',b = 'b' [a,b] = [b,a]
- 函数参数的定义
function f([a,b,c]){ return } f([1,2,3]) function f({x,y,z}){ return } f({x:'X',z:'Z',y:'Y'})
- 函数返回多个值
function returnArr(){ return ['A','B','C'] } let [a,b,c] = returnArr() function returnObj(){ return {a:'A',b:'B'} } let {a:dA,b:dB} = returnObj()
- JSON数据的解析
let json = { id:123, state:'A', point:[102,110] } let {id,state,point} = json console.log(id,state,point)
- 函数参数的默认值
function fn({ async = true, global = true, PE = 123 }={}){ return }
- 遍历Map解构
const map =new Map({first:'hello',second:'word'}) for (let [key,val] of obj){ console.log(key,val) }