解構(gòu)賦值
解構(gòu)賦值主要分為對(duì)象的解構(gòu)和數(shù)組的解構(gòu),在沒(méi)有解構(gòu)賦值的時(shí)候盒犹,我們賦值是這樣的
let arr = [0,1,2]
let a = arr[0]
let b = arr[1]
let c = arr[2]
這樣寫很繁瑣懂更,那么我們有沒(méi)辦法既聲明,又賦值急膀,更優(yōu)雅的寫法呢沮协?肯定是有的,那就是解構(gòu)賦值卓嫂,解構(gòu)賦值皂股,簡(jiǎn)單理解就是等號(hào)的左邊和右邊相等。
一命黔、數(shù)組的解構(gòu)賦值
let arr = [0,1,2]
let [a,b,c] = arr
console.log(a) // 0
console.log(b) // 1
console.log(c) // 2
但是很多時(shí)候呜呐,數(shù)據(jù)并非一一對(duì)應(yīng)的,并且我們希望得到一個(gè)默認(rèn)值
let arr = [,1,2]
let [a='我是默認(rèn)值',b,c] = arr
console.log(a) // '我是默認(rèn)值'
console.log(b) // 1
console.log(c) // 2
從這個(gè)例子可以看出悍募,在解構(gòu)賦值的過(guò)程中蘑辑,a=undefined時(shí),會(huì)使用默認(rèn)值
那么當(dāng)a=null時(shí)呢坠宴?當(dāng)a=null時(shí)洋魂,那么a就不會(huì)使用默認(rèn)值,而是使用null
// 數(shù)組的拼接
let a = [0,1,2]
let b = [3,4,5]
let c = a.concat(b)
console.log(c) // [0,1,2,3,4,5]
let d = [...a,...b]
console.log(d) // [0,1,2,3,4,5]
// 數(shù)組的克隆
// 假如我們簡(jiǎn)單地把一個(gè)數(shù)組賦值給另外一個(gè)變量
let a = [0,1,2,3]
let b = a
b.push(4)
console.log(a) // [0,1,2,3,4]
console.log(b) // [0,1,2,3,4]
因?yàn)檫@只是簡(jiǎn)單的把引用地址賦值給b喜鼓,而不是重新開(kāi)辟一個(gè)內(nèi)存地址副砍,所以
a和b共享了同一個(gè)內(nèi)存地址,該內(nèi)存地址的更改庄岖,會(huì)影響到所有引用該地址的變量
那么用下面的方法豁翎,把數(shù)組進(jìn)行克隆一份,互不影響
let a = [0,1,2,3]
let b = [...a]
b.push(4)
console.log(a) // [0,1,2,3]
console.log(b) // [0,1,2,3,4]
二隅忿、對(duì)象的解構(gòu)賦值
對(duì)象的解構(gòu)賦值和數(shù)組的解構(gòu)賦值其實(shí)類似心剥,但是數(shù)組的數(shù)組成員是有序的
而對(duì)象的屬性則是無(wú)序的邦尊,所以對(duì)象的解構(gòu)賦值簡(jiǎn)單理解是等號(hào)的左邊和右邊的結(jié)構(gòu)相同
let {name,age} = {name:"swr",age:28}
console.log(name) // 'swr'
console.log(age) // 28
對(duì)象的解構(gòu)賦值是根據(jù)key值進(jìn)行匹配
// 這里可以看出,左側(cè)的name和右側(cè)的name优烧,是互相匹配的key值
// 而左側(cè)的name匹配完成后蝉揍,再賦值給真正需要賦值的Name
let { name:Name,age } = { name:'swr',age:28 }
console.log(Name) // 'swr'
console.log(age) // 28
那么當(dāng)變量已經(jīng)被聲明了呢?
let name,age
// 需要用圓括號(hào)畦娄,包裹起來(lái)
({name,age} = {name:"swr",age:28})
console.log(name) // 'swr'
console.log(age) // 28
變量能否也設(shè)置默認(rèn)值又沾?
let {name="swr",age} = {age:28}
console.log(name) // 'swr'
console.log(age) // 28
// 這里規(guī)則和數(shù)組的解構(gòu)賦值一樣,當(dāng)name = undefined時(shí)熙卡,則會(huì)使用默認(rèn)值
let [a] = [{name:"swr",age:28}]
console.log(a) // {name:"swr",age:28}
let { length } = "hello swr"
console.log(length) // 9
function ajax({method,url,type='params'}){
console.log(method) // 'get'
console.log(url) // '/'
console.log(type) // 'params'
}
ajax({method:"get",url:"/"})
三捍掺、擴(kuò)展運(yùn)算符
我們先看下代碼,在以往再膳,我們給函數(shù)傳不確定參數(shù)數(shù)量時(shí)挺勿,是通過(guò)arguments來(lái)獲取的
function sum() {
console.log(arguments) // { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5, '5': 6 }
// 我們可以看出,arguments不是一個(gè)數(shù)組喂柒,而是一個(gè)偽數(shù)組
let total = 0
let { length } = arguments
for(let i = 0;i < length;i++){
total += arguments[i]
}
return total
}
console.log(sum(1,2,3,4,5,6)) // 21
接下來(lái)我們用擴(kuò)展運(yùn)算符看看
function sum(...args){ // 使用...擴(kuò)展運(yùn)算符
console.log(args) // [ 1, 2, 3, 4, 5, 6 ] args是一個(gè)數(shù)組
return eval(args.join('+'))
}
console.log(sum(1,2,3,4,5,6)) // 21
得到的args是一個(gè)數(shù)組不瓶,直接對(duì)數(shù)組進(jìn)行操作會(huì)比對(duì)偽數(shù)組進(jìn)行操作更加方便,還有一些注意點(diǎn)需要注意
// 正確的寫法 擴(kuò)展運(yùn)算符只能放在最后一個(gè)參數(shù)
function sum(a,b,...args){
console.log(a) // 1
console.log(b) // 2
console.log(args) // [ 3, 4, 5, 6 ]
}
sum(1,2,3,4,5,6)
// 錯(cuò)誤的寫法 擴(kuò)展運(yùn)算符只能放在最后一個(gè)參數(shù)
function sum(...args,a,b){
// 報(bào)錯(cuò)
}
sum(1,2,3,4,5,6)
我們可以對(duì)比下擴(kuò)展運(yùn)算符的方便之處
// 以往我們是這樣拼接數(shù)組的
let arr1 = [1,2,3]
let arr2 = [4,5,6]
let arr3 = arr1.concat(arr2)
console.log(arr3) // [ 1, 2, 3, 4, 5, 6 ]
// 現(xiàn)在我們用擴(kuò)展運(yùn)算符看看
let arr1 = [1,2,3]
let arr2 = [4,5,6]
let arr3 = [...arr1,...arr2]
console.log(arr3) // [ 1, 2, 3, 4, 5, 6 ]
// 以往我們這樣來(lái)取數(shù)組中最大的值
function max(...args){
return Math.max.apply(null,args)
}
console.log(max(1,2,3,4,5,6)) // 6
// 現(xiàn)在我們用擴(kuò)展運(yùn)算符看看
function max(...args){
return Math.max(...args) // 把a(bǔ)rgs [1,2,3,4,5,6]展開(kāi)為1,2,3,4,5,6
}
console.log(max(1,2,3,4,5,6)) // 6
// 擴(kuò)展運(yùn)算符可以把a(bǔ)rgument轉(zhuǎn)為數(shù)組
function max(){
console.log(arguments) // { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5, '5': 6 }
let arr = [...arguments]
console.log(arr) // [1,2,3,4,5,6]
}
max(1,2,3,4,5,6)
// 但是擴(kuò)展運(yùn)算符不能把偽數(shù)組轉(zhuǎn)為數(shù)組(除了有迭代器iterator的偽數(shù)組灾杰,如arguments)
let likeArr = { "0":1,"1":2,"length":2 }
let arr = [...likeArr] // 報(bào)錯(cuò) TypeError: likeArr is not iterable
// 但是可以用Array.from把偽數(shù)組轉(zhuǎn)為數(shù)組
let likeArr = { "0":1,"1":2,"length":2 }
let arr = Array.from(likeArr)
console.log(arr) // [1,2]
對(duì)象也可以使用擴(kuò)展運(yùn)算符
// 以往我們這樣合并對(duì)象
let name = { name:"邵威儒" }
let age = { age:28 }
let person = {}
Object.assign(person,name,age)
console.log(person) // { name: '邵威儒', age: 28 }
// 使用擴(kuò)展運(yùn)算符
let name = { name:"邵威儒" }
let age = { age:28 }
let person = {...name,...age}
console.log(person) // { name: '邵威儒', age: 28 }
需要注意的是蚊丐,通過(guò)擴(kuò)展運(yùn)算符和Object.assign對(duì)對(duì)象進(jìn)行合并的行為,是屬于淺拷貝艳吠,那么我們?cè)陂_(kāi)發(fā)當(dāng)中麦备,經(jīng)常需要對(duì)對(duì)象進(jìn)行深拷貝,接下來(lái)我們看看如何進(jìn)行深拷貝昭娩。
方法一:利用JSON.stringify和JSON.parse
let swr = {
name:"邵威儒",
age:28,
pets:['小黃']
}
let swrcopy = JSON.parse(JSON.stringify(swr))
console.log(swrcopy) // { name: '邵威儒', age: 28, pets: [ '小黃' ] }
// 此時(shí)我們新增swr的屬性
swr.pets.push('旺財(cái)')
console.log(swr) // { name: '邵威儒', age: 28, pets: [ '小黃', '旺財(cái)' ] }
// 但是swrcopy卻不會(huì)受swr影響
console.log(swrcopy) // { name: '邵威儒', age: 28, pets: [ '小黃' ] }
這種方式進(jìn)行深拷貝凛篙,只針對(duì)json數(shù)據(jù)這樣的鍵值對(duì)有效
對(duì)于函數(shù)等等反而無(wú)效,不好用栏渺,接著繼續(xù)看方法二呛梆、三。
方法二
function deepCopy(fromObj,toObj) { // 深拷貝函數(shù)
// 容錯(cuò)
if(fromObj === null) return null // 當(dāng)fromObj為null
if(fromObj instanceof RegExp) return new RegExp(fromObj) // 當(dāng)fromObj為正則
if(fromObj instanceof Date) return new Date(fromObj) // 當(dāng)fromObj為Date
toObj = toObj || {}
for(let key in fromObj){ // 遍歷
if(typeof fromObj[key] !== 'object'){ // 是否為對(duì)象
toObj[key] = fromObj[key] // 如果為普通值磕诊,則直接賦值
}else{
if(fromObj[key] === null){
toObj[key] = null
}else{
toObj[key] = new fromObj[key].constructor // 如果為object填物,則new這個(gè)object指向的構(gòu)造函數(shù)
deepCopy(fromObj[key],toObj[key]) // 遞歸
}
}
}
return toObj
}
let dog = {
name:"小白",
sex:"公",
firends:[
{
name:"小黃",
sex:"母"
}
]
}
let dogcopy = deepCopy(dog)
// 此時(shí)我們把dog的屬性進(jìn)行增加
dog.firends.push({name:"小紅",sex:"母"})
console.log(dog) // { name: '小白',
sex: '公',
firends: [ { name: '小黃', sex: '母' }, { name: '小紅', sex: '母' } ] }
// 當(dāng)我們打印dogcopy,會(huì)發(fā)現(xiàn)dogcopy不會(huì)受dog的影響
console.log(dogcopy) // { name: '小白',
sex: '公',
firends: [ { name: '小黃', sex: '母' } ] }
方法三
let dog = {
name:"小白",
sex:"公",
firends:[
{
name:"小黃",
sex:"母"
}
]
}
function deepCopy(obj) {
if(obj === null) return null
if(typeof obj !== 'object') return obj
if(obj instanceof RegExp) return new RegExp(obj)
if(obj instanceof Date) return new Date(obj)
let newObj = new obj.constructor
for(let key in obj){
newObj[key] = deepCopy(obj[key])
}
return newObj
}
let dogcopy = deepCopy(dog)
dog.firends.push({name:"小紅",sex:"母"})
console.log(dogcopy)