最近也一直會用javascript,然后中間使用的一些組件其弊,如Echarts 會有非常復雜的配置文件,而大部分配置可能都是一樣的膀斋,所以想著寫一份通用配置梭伐,然后,其他地方需要使用的時候仰担,用這份配置深拷貝一份配置糊识,然后在上面繼續(xù)改。就如下:
<script>
const defaultOpt = {
key1: xxx,
key2: {
dd: ee
},
.....
};
// deepCopy為某個實現(xiàn)深拷貝的方法
const opt1 = deepCopy(defaultOpt);
opt1.....
const opt2 = deepCopy(defaultOpt);
opt2.....
</script>
深拷貝和淺拷貝
這里也涉及到一個深拷貝和淺拷貝的概念摔蓝。javascript中存儲對象都是存地址的赂苗,所以淺拷貝是都指向同一塊內(nèi)存區(qū)塊,而深拷貝則是另外開辟了一塊區(qū)域贮尉。下面實例也可以看出這一點:
<script>
// 淺拷貝
const a = {
t: 1,
p: 'gg'
};
const b = a;
b.t = 3;
console.log(a); // {t: 3, p: 'gg'}
console.log(b); // {t: 3, p: 'gg'}
//深拷貝
const c = {
t: 1,
p: 'gg'
};
const d = deepCopy(c);
d.t = 3;
console.log(c); // {t: 1, p: 'gg'}
console.log(d); // {t: 3, p: 'gg'}
</script>
可以明顯看出拌滋,淺拷貝在改變其中一個值時,會導致其他也一起改變猜谚,而深拷貝不會败砂。
Object.assign()
我需要的是深拷貝的方法,然后發(fā)現(xiàn)原來es6 中有Object.assign() 這個方法魏铅,感覺可以拿來用了昌犹。
貼一下兩個官方例子:
//1.
<script>
// Cloning an object
var obj = {
a: 1
};
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
</script>
//2.
<script>
// Merging objects
var o1 = {
a: 1
};
var o2 = {
b: 2
};
var o3 = {
c: 3
};
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, target object itself is changed.
</script>
是不是很完美,又可以clone又可以merge览芳。在我這種情況下斜姥,我覺得我的代碼量又可以減少了,比如:
<script>
const defaultOpt = {
title: 'hello',
name: 'oo',
type: 'line'
};
// 原來可能需要這樣
const opt1 = deepCopy(a);
opt1.title = 'opt1';
opt1.type = 'bar';
opt1.extra = 'extra'; // 額外增加配置
// 現(xiàn)在只要這樣
const opt2 = Object.assign({}, a, {
title: 'opt2',
type: 'bar',
extra: 'extra'
});
</script>
不過沧竟,很快疾渴,問題出現(xiàn)了,那就是
merge和我想象的不一樣
<script>
const defaultOpt = {
title: {
text: 'hello world',
subtext: 'It\'s my world.'
}
};
const opt = Object.assign({}, defaultOpt, {
title: {
subtext: 'Yes, your world.'
}
});
console.log(opt);
// 預期結(jié)果
{
title: {
text: 'hello world',
subtext: 'Yes, your world.'
}
}
// 實際結(jié)果
{
title: {
subtext: 'Yes, your world.'
}
}
</script>
原本想的是它只會覆蓋subtext 屯仗,然而其實它直接覆蓋了整個title 搞坝,這個讓我比較郁悶,相當于它只merge根屬性魁袜,下面的就不做處理了桩撮。
代碼只能重構(gòu)成相對麻煩一點的:
<script>
const defaultOpt = {
title: {
text: 'hello world',
subtext: 'It\'s my world.'
}
};
const opt = Object.assign({}, defaultOpt);
opt.title.subtext = 'Yes, your world.';
console.log(opt);
// 結(jié)果正常
{
title: {
text: 'hello world',
subtext: 'Yes, your world.'
}
}
</script>
這樣用雖然麻煩一點,但是也還好峰弹,可以用了店量。不過。鞠呈。融师。很快,又出現(xiàn)問題了蚁吝,如下:
<script>
const defaultOpt = {
title: {
text: 'hello world',
subtext: 'It\'s my world.'
}
};
const opt1 = Object.assign({}, defaultOpt);
const opt2 = Object.assign({}, defaultOpt);
opt2.title.subtext = 'Yes, your world.';
console.log('opt1:');
console.log(opt1);
console.log('opt2:');
console.log(opt2);
// 結(jié)果
opt1: {
title: {
text: 'hello world',
subtext: 'Yes, your world.'
}
}
opt2: {
title: {
text: 'hello world',
subtext: 'Yes, your world.'
}
}
</script>
上面結(jié)果發(fā)現(xiàn)兩個配置變得一模一樣旱爆,而其實我們并沒有去更改opt1 的subtext 舀射,只是改了opt2 的。
這說明一點:在title 這一層只是簡單的淺拷貝 怀伦,而沒有繼續(xù)深入的深拷貝脆烟。
這里不經(jīng)讓我懷疑這個接口到底是怎么實現(xiàn)的,它到底是不是和我所想的一樣房待。
翻了一下官方文檔邢羔,發(fā)現(xiàn)它寫得一個Polyfill ,代碼我加了點注釋如下:
<script>
if (!Object.assign) {
// 定義assign方法
Object.defineProperty(Object, 'assign', {
enumerable: false,
configurable: true,
writable: true,
value: function (target) { // assign方法的第一個參數(shù)
'use strict';
// 第一個參數(shù)為空桑孩,則拋錯
if (target === undefined || target === null) {
throw new TypeError('Cannot convert first argument to object');
}
var to = Object(target);
// 遍歷剩余所有參數(shù)
for (var i = 1; i < arguments.length; i++) {
var nextSource = arguments[i];
// 參數(shù)為空拜鹤,則跳過,繼續(xù)下一個
if (nextSource === undefined || nextSource === null) {
continue;
}
nextSource = Object(nextSource);
// 獲取改參數(shù)的所有key值流椒,并遍歷
var keysArray = Object.keys(nextSource);
for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
var nextKey = keysArray[nextIndex];
var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
// 如果不為空?且可枚舉敏簿,則直接淺拷貝賦值
if (desc !== undefined && desc.enumerable) {
to[nextKey] = nextSource[nextKey];
}
}
}
return to;
}
});
}
</script>
上面的代碼可以直接說明它只對頂層屬性做了賦值,完全沒有繼續(xù)做遞歸之類的把所有下一層的屬性做深拷貝镣隶。
總結(jié)
Object.assign()
只是一級屬性復制极谊,比淺拷貝多深拷貝了一層而已诡右。用的時候安岂,還是要注意這個問題的。
附
發(fā)現(xiàn)一個可以簡單實現(xiàn)深拷貝的方法帆吻,當然域那,有一定限制,如下:
const obj1 = JSON.parse(JSON.stringify(obj));
思路就是將一個對象轉(zhuǎn)成json字符串猜煮,然后又將字符串轉(zhuǎn)回對象次员。
轉(zhuǎn)載至:http://blog.csdn.net/waiterwaiter/article/details/50267787