ES6(3)数组和对象的结构赋值、`...`运算符

238 阅读6分钟

解构赋值:按照一个数据值的结构,快速解析获取到其中的内容

字符串、数字、数组、对象都可以解构赋值(null、undefined不行)但是我们一般只给数组和对象进行解构赋值

让等号左边的数据结构和右边的一样,左边可以创建一些变量,快速获取到右边对应位置的值**解构赋值**

在解构的时候可以给变量设置默认值(默认赋值):如果当前变量对应结构的这一项没有值(或者是undefined),变量用默认值;如果当前变量对应结构的这一项null会把null赋值给变量

...作为剩余运算符时,把除前面以外的项都放在一个数组中;剩余运算符必须处于结构中的最后面,后面不能有东西

数组解构赋值

ler arr=[12,23,34];

//获取每一项
let [a,b,c]=arr;
console.log(a,b,c)   //12,23,34

//只获取第一项
let [a]=arr;
console.log(a)   //12


//只取某一项
let [,,c]=arr;
console.log(c)   //34


//获取第一项和最后一项
let [a, ,c]=arr;
console.log(a,c)   //12 34

//把第一项以外的,以一个新数组返回
let [a,..b]=arr;
console.log(a,b)   //12 [23,34]

// 剩余运算符必须处于结构中的最后面,后面不能有东西。
let [a,..b,c]=arr;
console.log(a,b,c)   //报错  语法错误 


//在解构的时候可以给变量设置默认值:如果当前变量对应结构的这一项没有值,变量用默认值
let arr2=[1]
let [a,b=0]=arr2;
console.log(a,b)   //1 0

//如果当前变量对应结构的这一项null会把null赋值给变量
let arr2=[1,null]
let [a,b=0]=arr2;
console.log(b)  //null

//两个变量互换值
let a=12;
let b=13;
//=>ab互换位置
//传统
let c=a;
a=b;
b=c;
//解构赋值
[a,b]=[b,a]
console.log(a,b)   //13  12

对象解构赋值

默认情况下要求左侧变量名和对象中的属性名要一致

设置默认值必须用等号,前面带let或者作为函数的形参时这个变量才能当变量使用

let obj={name:'xxx',age:25,sex:0}
let {name,age}=obj;
console.log(name,age)  //'xxx'  '25'

//只获取某一个
let {sex}=obj;
console.log(sex)    //0

//给解构的属性名起别名,作为变量,起完别名原来的变量名就不能用了
let {sex:sexAA}=obj;
console.log(sex)    //报错  sex undefined
console.log(sexAA)  //0

//给不存在的属性设置默认值  (必须用=号)
let {id=10}=obj;
console.log(id)    //10


//真实使用   函数
let fn=function({name='aaa',age=18} = {}){   //把传递的对象解构了(不传值默认为空对象),解构的时候,可以把传递进来对象中如果没有某个属性,我们赋值默认值
	console.log(name,age)
}
fn({
	name:'xx',
	age:25
	
})

//步骤解析

let fn=function(option = {}){   
	let {name='aaa',age=18}=option 
}
fn({
	nameL:'xx',
	age:25
	
})

例题

let value={name:'xxx',age:25,score:[12,23,34,45] }
//a='xxx'
//b=12
//c=[23,24,45]

let  {name:a,score:[b,...c]} =value;
console.log(a,b,c)

“...” 在ES6中的两种含义

剩余运算符:把除前面以外的项都放在一个数组中

拓展运算符( 展开运算符):把数组(对象、类数组)中的每一项展开 xxx,xxx,xxx...

1、放在被赋值一方是剩余运算符。放在赋值一方是扩展运算符

2、当三个点在等号右边,或者放在实参上是展开运算符

3、当三个点(...)在等号左边,或者放在形参上是剩余运算符

剩余运算符

当三个点(...)在等号左边,或者放在形参上

let arr=[12,23,34]
let [...arg] = arr;   //跟arr.slice(0)一个效果
console.log(arg)   //[12,23,34]


//arguments利用 剩余运算符
function fn(context,...arg){
	//获取传递值中的第一个和剩下的
	console.log(context)
	console.log(arg)   //arg 是数组 ,而arguments是类数组
	
}
var obj={name:'aaa'}
fn(obj,10,20)



function sum(...arg){
	//传递几个实参,arg就存储多少个,此时的arg和arguments一样的,区别是arg是一个数组,arguments是类数组
}

展开运算符

当三个点在等号右边,或者放在实参上

展开后必须有容器

把数组中的每一项分别传递给一个函数,此时我们使用展开运算符把数组展开即可

把原有对象展开(克隆),放到新对象中

数组的克隆用slice,或者let newArr=[...arr,100]

let arr= [12,23,34];
//Math.max(...arr)

let fn=function(a,b,c){
	console.log(a,b,c)
}
//fn(arr)    //arr  undefined   undefined
fn(...arr)    //=>fn(12,23,34)  => 打印 12 23  34



//克隆对象
let obj= {name:'xxx',age:20}
let newObj={...obj,sex:0}   //{name:'xxx',age:20,sex:0}

//克隆数组

let arr=[10,20]
let newArr=[...arr,100]   //[10,20,100]
let newArr2=[...arr,100,...arr]   //[10,20,100,10,20]


let max =Math.max(1,2,3);
//想要处理 Math.max([1,2,3]) 也可用
//es5写法
Math.max.apply(null,[1,2,3])  //3
//es6写法
var arr=[1,2,3];
Math.max(...arr)		//Math.max(...arr) =>Math.max(1,2,3) 3

实现任意数求平均数(去掉数字中的最大最小,然后求平均数,保留小数点后两位)

let fn =function(){
	//=>arguments:类数组(不能直接调用Array的方法)
	//1、先给arguments排序(不能直接用sort)去掉首位
	//2、把剩下的求和,除以总长度
	let arr=[];
	for(let i=0;i<arguments.length;i++){
		arr.push(arguments[i])
    }
    
    arr.sort(function(a,b){
		return a-b;
	})
	arr.pop();
	arr.shift();
	//return (eval(arr.toString().replace(/,/g,'+'))/arr.length).toFixed(2);  也行
	return (eval(arr.join('+'))/arr.length).toFixed(2);
}

fn(10,9.8,9.5,8.7,8.8,8,9.2)

内置slice利用call能把类数组arguments转化为数组arr的原理:把内置slice的this指向arguments

前提:类数组和数组类似,都有length和索引(字符串也符合这个前提)

重写数组的slice方法实现:arr.mySlice() 相当于把arr克隆为一份新数组

凡是有length和索引的利用[].slice().call(xxx) 都能转化为数组 ;比如把字符串转化为数组

把字符串转化为数组的方法变为了两种:字符串的split;[].slice().call(str)

Array.prototype.mySlice=function(){
	//this:arr
	var newArr=[]
	for(let i=0;i<this.length;i++){
		newArr.push(this[i])
    }
    return newArr;
	/**
	let arr=[];
	for(let i=0;i<arguments.length;i++){
		arr.push(arguments[i])
    }
    */
    //通过代码对比发现只要把this指向arguments就可以实现 类数组转化为数组
    //call、apply都可以
}
let arr=[12,23,34]
arr.mySlice();    //[12, 23, 34]

最终代码:

let fn =function(){
	//=>把arguments类数组转换为数组(把数组克隆一份一抹一样的,最后存储在新的数组中)
	//调用内置的slice方法的方式:Array.prototype.slice() 或者  [].slice()
	let arr=[].slice().call(arguments)    //把类数组arguments转化为数组arr
            //原理:slice()在mn两个参数都不传的时候是克隆,
            //[].slice() slice中的this是[]
            //利用call方法把slice中的this转化为了arguments
            //相当于克隆了arguments 
            arr.sort(function(a,b){
            return a-b;
	})
	arr.pop();
	arr.shift();
	//return (eval(arr.toString().replace(/,/g,'+'))/arr.length).toFixed(2);  也行
	return (eval(arr.join('+'))/arr.length).toFixed(2);
}

fn(10,9.8,9.5,8.7,8.8,8,9.2)

[].slice().call('liyapei')
//=>['l','i','y','a','p','e','i'] 

借用sort给arguments排序

[].sort.call(arguments,function(a,b){
	return a-b;
})

数组的方法用call都能被arguments借用

利用ES6把类数组转化为数组let arr=[...arguments]或者let arr=Array.from(arguments)或者(...arr)直接解构

let fn =function(){
	let arr=[...arguments]  //把类数组转化为数组
	//或者,let arr=Array.from(arguments)
	arr.sort(function(a,b){
		return a-b;
	})
	arr.pop();
	arr.shift();
	//return (eval(arr.toString().replace(/,/g,'+'))/arr.length).toFixed(2);  也行
	return (eval(arr.join('+'))/arr.length).toFixed(2);
}

fn(10,9.8,9.5,8.7,8.8,8,9.2)

let fn =function(...arr){
	arr.sort(function(a,b){
		return a-b;
	})
	arr.pop();
	arr.shift();
	//return (eval(arr.toString().replace(/,/g,'+'))/arr.length).toFixed(2);  也行
	return (eval(arr.join('+'))/arr.length).toFixed(2);
}

fn(10,9.8,9.5,8.7,8.8,8,9.2)

把类数组转化为数组:

1. let arr=[].slice().call(arguments)

2. let arr=[...arguments]

3. let arr=Array.from(arguments)

4. function(...arr)直接解构