在ES6中新增了擴展運算符能夠對數組和對象進行操做。有時候會遇到數組和對象的拷貝,可能會用到擴展運算符。那麼這個擴展運算符究竟是深拷貝仍是淺拷貝呢?es6
一.、使用擴展運算符拷貝數組
首先是下面的代碼。ui
let a = [1,2,3]; let b = [...a];
a == b // false
結果是false,這是很容易知道的,畢竟這個賦值操做符是由區別的。接下來將數組的只進行改變,又會怎樣呢;this
let a = [1,2,3]; let b = [...a]; a[0] = 11; console.log(a); // [ 11, 2, 3 ] console.log(b); // [ 1, 2, 3 ]
發現a的值發生改變以後b的值並無發生改變。因此就是深拷貝了嗎?別急,接下來將數組中的元素設爲引用類型。spa
let a = [1,2,[1,2,3]]; let b = [...a]; a[2][1] = 11; console.log(a); // [ 1, 2, [ 1, 11, 3 ] ] console.log(b); // [ 1, 2, [ 1, 11, 3 ] ]
console.log(a[2] === b[2]); // true
此次的結果就有意思了,若是改變數組中的引用類型的元素中的值,此時a和b的值都會改變,而且a和b中的引用類型全等,也就是說地址是相同的。那麼爲何是這樣的呢?插件
二.、緣由code
首先此分析僅爲本人目前的認知。對象
對於數組中的擴展運算符只是一個淺拷貝,僅對引用類型數據的第一層進行了拷貝,而假若再深的層次就不會進行拷貝。blog
另外對象的擴展運算符和數組是同樣的。遞歸
let a = { name : "Jyy", msg : { age : 29 } } let b = {...a}; console.log(a == b); // false console.log(a.msg == b.msg); // true; a.msg = { age : "28" } console.log(a); // { name: 'Jyy', msg: { age: '28' } } console.log(b); // { name: 'Jyy', msg: { age: 29 } }
3、深拷貝和淺拷貝的方法
1.淺拷貝方法
上面的例子已經看出來es6中的擴展運算符僅僅對引用類型進行了第一層的拷貝。除了es6的擴展運算符還有其餘方法
對象:
使用Object.assign()
Object.assign()用於對象的合併,若是第一個參數爲{},則可對後面的對象參數進行拷貝
let a = { name : "Jyy", msg : { age : 29 } } let b = Object.assign({},a); console.log(a == b); // false console.log(a.msg == b.msg); // true; a.msg = { age : "28" } console.log(a); // { name: 'Jyy', msg: { age: '28' } } console.log(b); // { name: 'Jyy', msg: { age: 29 } }
數組:
數組的淺拷貝的方法不少
a.使用slice()
slice能夠截取數組中部分的元素,若參數爲空,則可對數組進行淺拷貝
let a = [1,2,[1,2,3]]; let b = a.slice(); console.log(a == b); // false a[2][1] = 11; a[0] = 11; console.log(a); // [ 11, 2, [ 1, 11, 3 ] ] console.log(b); // [ 1, 2, [ 1, 11, 3 ] ] console.log(a[2] == b[2]); // true
b.使用concat()
concat能夠對數組進行合併,若參數爲空,亦可對數組進行淺拷貝
let a = [1,2,[1,2,3]]; let b = a.concat(); console.log(a == b); // false a[2][1] = 11; a[0] = 11; console.log(a); // [ 11, 2, [ 1, 11, 3 ] ] console.log(b); // [ 1, 2, [ 1, 11, 3 ] ] console.log(a[2] == b[2]); // true
c.使用Array.from()
let a = [1,2,[1,2,3]]; let b = Array.from(a); console.log(a == b); // false a[2][1] = 11; a[0] = 11; console.log(a); // [ 11, 2, [ 1, 11, 3 ] ] console.log(b); // [ 1, 2, [ 1, 11, 3 ] ] console.log(a[2] == b[2]); // true
2.深拷貝
對於深拷貝,數組和對象的方法是一致的
a.遞歸方法,就是用for循環一層一層的進行拷貝,具體代碼就不寫了
b.JSON.parse()
這個方法一般用於調用接口傳參或者是返回的字符串數據轉成對象。
let a = { name : "JYY", age : "25", msg : { addr : "hebei" } } b = JSON.parse(JSON.stringify(a)); console.log(a == b); // false console.log(a.msg == b.msg); // false a.msg.addr = "chengde"; console.log(a); // { name: 'JYY', age: '25', msg: { addr: 'chengde' } } console.log(b); // { name: 'JYY', age: '25', msg: { addr: 'hebei' } }
這個方法的弊端就是undefined
、function
、symbol
會在轉換過程當中被忽略
let a = { name : "JYY", age : "25", msg : { addr : "hebei" }, speek : function(){ console.log(this.name); } } b = JSON.parse(JSON.stringify(a)); console.log(a); // { name: 'JYY', height: Symbol(jyy), age: undefined, msg: { addr: 'chengde' },speek: [Function: speek] } console.log(b); // { name: 'JYY', msg: { addr: 'hebei' } }
c.使用第三方插件
好比lodash的深拷貝
const _ = require("lodash"); let syb = Symbol('jyy'); let a = { name : "JYY", height: syb, age : undefined, msg : { addr : "hebei" }, speek : function(){ console.log(this.name); } } let b = _.cloneDeep(a); console.log(a == b); // false console.log(a.msg == b.msg); // false console.log(a); // { name: 'JYY', height: Symbol(jyy), age: undefined, msg: { addr: 'chengde' },speek: [Function: speek] } console.log(b); // { name: 'JYY', height: Symbol(jyy), age: undefined, msg: { addr: 'chengde' },speek: [Function: speek] }