什么是解构赋值???
在Es6
中提供了更高效的变量赋值方法,可以按照一定模式,拆解数组,对象,字符串的结构给变量赋值。这种方式称为解构赋值。
解构赋值 : 拆解数据解构 来给变量赋值
数组的解构赋值
在es5
中如何拿到一个数组的索引项呢
var arr = [0,1,2];
var a = arr[0];//拿到索引0项
var b = arr[1];//拿到索引1项
var c = arr[2];//拿到索引2项
//声明了3个变量存储着数组中的索引值
console.log(a,b,c);
通过这种方式确实拿到了数组中对应的索引值的,但是获取数组中的索引居然用来3行代码,那es6
增加了一个方法解决了es5
这种获取数组中的索引项这种很麻烦的问题
那就是 数组的解构赋值
var arr = [0,1,2];
let [a,b,c] = arr;//完全解构
//左侧的是一种匹配模式(匹配模式里面的名字就相当于变量),来匹配右侧的数组的结构
console.log(a,b,c);//打印0 1 2
arr
的数组的[0,1,2]
,接下来我用左侧的一种匹配的模式,来匹配右侧的数组的。
右侧是数组,左侧是按照数组的匹配模式来匹配的然后变量就会一一对应,a-->0,b-->1,c-->2
,拆解数组的结构来给a
,b
,c
赋值,这就是结构赋值(拆解数据结构来给变量赋值)
如果左边模式只匹配到右边模式的所有,则这个解构是完全解构
如果左边模式只匹配到右边模式的一部分,那会怎么样??
let [a,b] = [0,1,2];//那么a收到的是0,b收到的是1,那么2没有变量接收(也不会报错)
console.log(a,b)//打印出来 0 1
这形式叫做不完全解构(三个数据全被接收叫做 完全解构)
我这个数据总共有3
个,可是接收数据的变量是两个,也就是还有一个数据没有被接收,则这个解构是不完全解构
如果左边模式只匹配到右边模式的一部分,则这个解构是不完全解构
如果左侧模式中的个别变量没有匹配到右边模式,那会怎么样??
let [a,b,c,d] = [0,1,2];
console.log(a,b,c,d)//打印出来 0 1 2 undefined;
a-->0 , b-->1 , c-->2 , d-->undefined(默认值)
d
如果没有匹配到值 则d
的值为默认值undefined
当一个变量要匹配某个数据,要匹配的数据没有提供此数据那么就是默认值undefined
如果左侧模式中的个别变量没有匹配到右边模式,则这个解构是不成功解构
在数组解构赋值中,...
操作符是用来干什么的???
情况一
let [a,...b] = [0,1,2];
console.log(a,b)//打印 0 [1,2]
a-->0,...b
(该变量会接收0后面的所有数据) -->[1,2]
情况二
let [a,b,...c] = [0,1,2];// a-->0,b-->1,c-->[2]
console.log(a,b,c);//打印 0 1 [2]
你只要是...变量
,他会认为这个变量接收一组数据,即使你这种模式只能匹配到一个数据但是他还会以数组的形式展现出来的
情况三
let [a,b,c,...d] = [0,1,2];//a-->0,b-->1,c-->2,d-->[]
console.log(a,b,c,d);//打印 0 1 2 []
这个变量b
接收不到数据,JS依然认为变量b
接收的是一组数据,那就是为空([]
)
情况四
let [...a,b] = [0,1,2];
//...变量只能在匹配模式的最后面,来匹配剩余数据
console.log(a,b);
//会报错(剩余的参数必须是最后一个变量)只要一个变量前面有...那么他就会接收这后续所有的数据
...变量
,这个变量必须放置在匹配模式的最后面,因为JS系统会认为...变量
接收这后续的所有数据的
...变量
- 这个变量必须写在匹配模式的最后面
- 这个变量会匹配到剩余的所有数据
在解构赋值中,要匹配的变量没有匹配到数据,我们可以设置默认值
let [a,b] = [1];//a=1 b=undefined
console.log(a,b);
在这中情况b
是没有要匹配的数据的结果是undefined
,那么我们可以给b
设置一个默认值
如何设置数组解构的默认值
let [a,b=5] = [1]; //a=1 b=5
//当b匹配到的数据是undefined的时候就会自动的给b赋值值是5
console.log(a,b);
当要匹配的变量是undefined
的时候找不到数据,我会给你设置默认值
当解构是不成功解构时,要匹配变量是undefined
时,我们可以人为设置变量的默认值
情况一
function auto(){
console.log('我auto函数执行了')
return 'huasheng';
};
let [a,b=auto()] = [1]; // '我auto函数执行了' a=1 b='huasheng'
console.log(a,b)
a=1 b是undefined
,一旦b
是undefined
就是把auto
函数的结果赋值给变量b
,设置默认值,auto
执行的结果是huasheng
,使以我会把auto
执行的结果给变量b
情况二
function auto(){
console.log('我auto函数执行了')
return 'huasheng';
};
let [a,b=auto()] = [1,2]; //a=1 b=2
console.log(a,b)
如果b在结构赋值中,分配到数据那么默认值就不会生效
给变量设置默认值的时候,实现该变量值必须是undefined
(没有分配到任何数据函数才会执行),如果b
分配到数据了那么就不会执行默认值了
当没有任何要匹配的数据(undefined
),才会执行默认值,在设置变量的默认值时,总是惰性求值的。
数组解构赋值练习
// 第一题
{
let [a,b,c] = [1,3,4];
console.log(a,b,c);// a=1 b=3 c=4
}
// 第二题
{
let [a,[b,c]] = [1,[3,4]];//等号右侧数组里面,第二个是二维数组
console.log(a,b,c);// a=1 b=3 c=4
};//结构赋值是给变量赋值的(拆解数据给变量赋值),不存在b=[3],c=[4]这种情况的
// 第三题
{
let [a,b,c] = [1,[3],4];
console.log(a,b,c)//a=1 b=[3] c=4 声明变量匹配等号右边的数据
//也可以理解为是按照索引项来匹配数据的
}
// 第四题
{
let [a,[b],c] = [1,[3,4]];
console.log(a,b,c);//a=1 b=3 c=undefined(按照对应的索引匹配一个符合条件的数据)
}
// 第五题
{
let [a,,c] = [1,,4];
console.log(a,c);//a=1 c=4
}
// 第六题
{
let [a,...b] = [1,2,3];
console.log(a,b);//a=1 b=[2,3]
}
对象的解构赋值
对象解构的简洁写法(属性名字和变量是一致的)
let {name,age} = {name:'huasheng',age:28};常用的对象的解析赋值
console.log(name,age);'huasheng' 28
let
前面的{}
是一种匹配模式,是专门用来匹配对象的,当前要匹配的对象是花括号开始花括号结束,使用为了匹配对象这种数据格式,我必须声明一种像对象的匹配模式要匹配你对象中的值
匹配到name
属性声明name
变量,并且给name
变量赋值存储字符串'huasheng'
,以及声明了age
变量匹配到age
属性存储值是28
这种写法表示。先匹配name
属性(你等号右侧是有name
属性的),再次声明了一个name
变量,并且这name
变量存储了字符串'huasheng'
age
属性匹配等号右侧的age
属性,再次声明了一个age
变量来存储值28
的
数组的匹配模型是按照索引来匹配的,对象的匹配模式是按照属性名字来匹配的
其实上面的写法并不完善
对象解构的完整写法
let {name:name , age:age} = {name:'huasheng',age:28};
//属性名字和你要声明的变量是一致的就可以写成一个了(匹配成功就可以声明变量name了)
console.log(name,age)
当你的匹配模式和你的变量是完全一致的情况下,可以简写成一个属性名
et {name:a , age:b} = {name:'huasheng',age:28};
console.log(name,age)
对象的匹配模式,匹配到了name
属性,并且声明的变量a值是'huasheng'
以上两种方法是,值是完全相等的,都是用对象匹配模式匹配到了name
属性,值都是’huasheng'
就是声明的变量不同,一个是变量name
一个是变量b
,都是成功匹配到了name
属性声明变量并赋值(匹配模式是name
,要匹配的数据是age
)匹配模型和匹配数据的名字不相等这匹配不成功就不能声明name
变量了
那如果匹配模式颠倒顺序了呢??
let {age:age,name:name} = {name:'huasheng',age:28};
//他本质是按照属性名字来匹配数据的(颠倒顺序也没事)
console.log(name,age)
对象的结构是按照属性的名字来匹配的,当前等号右侧是一个对象,这个对象有一个age
属性。
等号左侧是一个数据解构的模式,而我的模式中就是专门匹配age
属性的,有age
属性匹配等号右侧的age
属性,匹配出来了声明变量age
变量,age
变量存储值28
let {age} = {name:'hausheng'};
console.log(age)//undefined
等号右侧有一个name
属性,然后匹配模式是用来匹配age
属性的,而等号右侧是没有age
属性的所以就匹配不到age
属性值是undefined
(默认值)
对象匹配模式,匹配不到数据,值是undefined
(默认值)
当对象匹配不到数据,是可以设置默认值的,那该怎么设置??
let {age:age=20} = {name:'hausheng'};//当age匹配不到数据时值是(undefined)启动默认值
console.log(age);
我要匹配等号右侧的age
属性,当前等号右侧是没有age
属性的是匹配不到的,一旦匹配不到age
属性我声明的age
变量就要启动它的默认值是20
对象解构赋值的应用
let {min,max} = Math;//这种匹配模式是匹配Math的min和max属性的并且声明了min和max变量,
//把Math对象现有的min,max方法赋值给变量min,max
console.log(min,max);//匹配到了Math对象上面的min函数和max函数
原始值的结构赋值
字符串的解构赋值 类似于数组的解构
let [a,b] = 'hello';//安装字符串的索引位置拆解数据结构给a,b赋值
console.log(a,b);//a=h b=e
等号右侧是一个字符串,字符串是可以拆解的(字符串也是按对应的索引位置有值的)他是有索引对应的值
那么该怎么接收剩余字符呢??(把字符串当做数组解构了)
let [a,b,...c] = 'hello';//
console.log(a,b,c);// a=h b=e c=["l", "l", "o"]
...c
表示这个变量c
将接收着使用数据并且是以数组的形式返回的,即使是3个字符我会把这3个字符打散在我的数组中存在,接收不到字符就是[]
数字的解构赋值 类似于对象的解构
let {toString} = 2;
console.log(toString)//他会把数字当做对象来解构
而这个数字是原始值,原始值不是对象,他会被new Number
函数包装成数字对象
当前是要拆解这个对象匹配toString
这个属性得到的是toString
这个函数
通过new Number
函数包装成数字对象,然后去找包装好了的数字对象中的值(JS内置)找到了就会返回相对应的函数,反之undefined
布尔的解构赋值 类似于对象的解构
let {toString} = false;//他会把布尔值当做对象来解析
console.log(toString);
布尔值是原始值,自然不会是对象,他会通过new Boolean
函数包装成一个布尔对象,然后查找里面的toString
函数(JS内置)自然是有这个函数,返回来的是函数体
数字的解构赋值和布尔值的解构赋值都是通过包装类,包装成一个对象,然后就查询(布尔对象,数字对象)里面的函数,这个函数都是JS内置的所以就会打印函数体,不是数字对象和布尔对象包装类型里面的内置函数就会返回
undefined
默认值
对象的结构解析练习题目
// 第一题
{
let obj = {
name:'huasheng',
fav:['beauty','money'],
};
let {a:name} = obj;//匹配模式的属性名和要匹配的数据名字相同才能匹配成功
//(否则是默认值undefined)
console.log(name);//打印huasheng
}
// 第二题
{
let obj = {
name:'huasheng',
fav:['beauty','money'],
};
let {name:a} = obj;//匹配模式name,匹配到了要obj的name,
// 声明变量a,并且赋值'huasheng'
console.log(a);//打印'huasheng'
}
// 第三题
{
let obj = {
name:'huasheng',
fav:['beauty','money'],
};
let {name:n,fav:f} = obj;//匹配模式匹配到了obj里面的,name和fav属性,
// 并且声明变量,分别n='huasheng' f=['beauty','money']
console.log(n,f);//打印 'huasheng' ['beauty','money']
}
// 第四题
{
let obj = {
p:[
'hello',
{y:'world'}
]
}
let { p : [x, {y}]} = obj;//1,对象匹配模式p要匹配数组[],成立 2,
//数组匹配模式x索引项0,匹配到了hello的索引项0声明变量x值是hello 3
//,对象匹配模式y:y 匹配到了y声明变量y值是world
console.log(x,y); //x=hello y=world
}
// 第五题
{
let obj = {
p:[
'hello',
{y:'world'}
]
}
let {p , p:[x , {y}]} = obj;
//1,对象匹配模式p:p,匹配到了obj声明变量p把obj里面的p赋值给变量p,
//2,数组匹配模式p匹配到了obj里面的p,x索引0匹配到了索引0的
//hello声明变量x把这个值赋值给x,3,对象匹配模式y:y,匹配到了y,并且声明变量y值是world
console.log(p,x,y);//打印数组p hello world
}
// 第六题
{
let {x:a=3} = {x:undefined};//对象匹配模式x匹配到了被匹配数据的x条件成立,
//声明变量a一看x值是undefined一旦是undefined就启动默认值是3 a=3
console.log(a);//打印3
}
// 第七题
{
let {x:a=3} = {x:null};//对象匹配模式x匹配到了被匹配属性的x条件成立,
//声明变量x值是null(只有是undefined才能启动默认值)
console.log(a);//打印null
}
// 第八题
{
const node = {
loc:{
start:{
line:1,
column:5
}
}
}
let { loc, loc:{start}, loc:{ start:{line} } } = node;
//1,对象匹配模式 loc:loc 匹配到了node里面的loc属性,
//条件成立声明变量值是loc{}大对象 ,2,对象匹配模式 start:start,
//匹配到了node里面的start属性条件成立,声明start变量值是start{}大对象,
//3,对象匹配模式 line:line 匹配到了node里面的line 条件成立声明line变量值是1
console.log(loc,start,line);//loc=loc{} start=start{} line=1
}