在使用Vue做項(xiàng)目的時(shí)候播瞳,通常會(huì)有許多組件間傳遞對(duì)象的情況掸刊。如果只是簡單的賦值的話(淺拷貝),是很危險(xiǎn)的赢乓,因?yàn)槟悴恢朗裁辞闆r下這個(gè)值就被修改了忧侧,還一臉蒙蔽,所以我們需要進(jìn)行深拷貝牌芋。深拷貝和淺拷貝的概念蚓炬,需要一點(diǎn)數(shù)據(jù)結(jié)構(gòu)的知識(shí)去了解。
聲明一個(gè)object1對(duì)象
var object1 = {
a:'a',
b:'b'
}
這時(shí)候我們來畫個(gè)內(nèi)存圖:聲明一個(gè)對(duì)象后在內(nèi)存內(nèi)某個(gè)地址上存入對(duì)象object的內(nèi)容躺屁,這個(gè)地址指向object1
然后把 對(duì)象1賦給對(duì)象2 var object2 = object1
這時(shí)候的內(nèi)存 我們來看一下
內(nèi)存內(nèi)同一個(gè)地址指向了兩個(gè)變量肯夏,其中一個(gè)變量內(nèi)容的改變都會(huì)影響這個(gè)地址內(nèi)存儲(chǔ)內(nèi)容的改變,這就是淺拷貝犀暑。
我們?cè)诮M件間傳遞對(duì)象的時(shí)候驯击,當(dāng)然不能進(jìn)行這么危險(xiǎn)的操作,應(yīng)該將內(nèi)存拷貝出去耐亏,使得另一個(gè)地址指向object2,這樣的拷貝就叫做深拷貝徊都。深拷貝之后兩個(gè)變量擁有相同的內(nèi)容,但是內(nèi)存地址不一樣广辰,互不影響暇矫。
那應(yīng)該怎么進(jìn)行深拷貝呢?择吊?
1袱耽、簡單粗暴的對(duì)象深拷貝
var object2 = JSON.parse( JSON.stringify(object1) )
簡單粗暴法沒有辦法深拷貝函數(shù),如果需要得自己封裝一個(gè)方法干发,去遞歸的深拷貝對(duì)象屬性朱巨。方法大家可以參考這篇文章 深入剖析 JavaScript 的深復(fù)制
2.在這里值得一提的是以下這種方式,這種方式看起來像是深拷貝枉长,其實(shí)是淺拷貝
function test() {
'use strict';
let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj1.a = 1;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj2.a = 2;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}
obj2.b.c = 3;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}}
Object.assign()方法將一個(gè)的對(duì)象上的屬性枚舉復(fù)制給另一個(gè)對(duì)象冀续,但是當(dāng)object2的值改變時(shí)也會(huì)改變object1。感興趣的同學(xué)可以去看看object.assign()接口的源碼必峰,你會(huì)發(fā)現(xiàn)object.assign()只是深拷貝了源對(duì)象的頂層屬性洪唐,并沒有遞歸的去進(jìn)行深拷貝,當(dāng)源對(duì)象的屬性值是一個(gè)指向?qū)ο蟮囊煤鹨希仓豢截惸莻€(gè)引用值凭需。
3问欠、 ES8中提供的新方法
ES8中提供了一個(gè)新方法: Object.getOwnPropertyDescriptors。MDN描述:該方法返回指定對(duì)象上一個(gè)自有屬性對(duì)應(yīng)的屬性描述符粒蜈。(自有屬性指的是直接賦予該對(duì)象的屬性顺献,不需要從原型鏈上進(jìn)行查找的屬性)。應(yīng)用如下:
let a = {name:'lili',age:9,birth:'1995-10-13',sex:'gril'}
console.info(Object.getOwnPropertyDescriptors(a))
/* {name: {…}, age: {…}, birth: {…}, sex: {…}}
age
:
{value: 9, writable: true, enumerable: true, configurable: true}
birth
:
{value: "1995-10-13", writable: true, enumerable: true, configurable: true}
name
:
{value: "lili", writable: true, enumerable: true, configurable: true}
sex
:
{value: "gril", writable: true, enumerable: true, configurable: true}*/
結(jié)合Object.defineProperties()方法枯怖,該方法直接在一個(gè)對(duì)象上定義新的屬性或修改現(xiàn)有屬性注整,并返回該對(duì)象,可以實(shí)現(xiàn)對(duì)象的深拷貝,結(jié)合上一個(gè)例子:
let obj1 = { a: 0 , b: { c: 0}};
console.info(Object.getOwnPropertyDescriptors(obj1))
/* {a:0,b:{c:0}}*/
obj1.b.c = 233;
obj1.a = 22;
console.info(Object.getOwnPropertyDescriptors(obj1))
/* {a:22,b:{c:233}}*/
let obj2 = {}
Object.defineProperties(obj2,Object.getOwnPropertyDescriptors(obj1))
console.info( obj2 )
/* {a:22,b:{c:233}}*/
4、 遞歸遍歷函數(shù)
function deep(obj){
if(typeof obj !== 'Object') return;
var newObj = obj instanceof Array ? [] : {};
for(var key in obj){
newobj[key] = typeof obj === 'Object' ? deep(obj(key)): obj(key)
}
return newobj
}