前阵子刚写完 JavaScript,差不多可以开始进行 Vue 的时候,突然想起在 Vue 开发的时候总是搞不清楚什麽是浅拷贝 ( Shallow Copy ) ,什麽是深拷贝 ( Deep Copy ),也因此在练习的时候很常出现令自己感到问号的错误,那麽今天也算是为了让 Vue 的开发更顺畅,来研究一下这两种写法。
只能对第一层进行浅层复制,如果有第二层结构,还是会依据参考特性作处理;也就是说,在第二层开始他们的记忆体位置还是一样的,因此依然会覆盖掉原物件。
浅层拷贝分成两种方法:
Object.assign
Object.assign()
方法,被用来复制一个或多个物件,回传的值则为复制的该物件。
Object.assign(target, ...sources)
target / 目标物件
sources / 复制来源物件
范例:
let ary = ['齐天大圣孙悟空', '猪八戒', '沙悟净', '唐僧'];
let obj = {woman1: '白骨精', woman2: '紫霞仙子', man: '牛魔王'};
let aryNew = Object.assign([], ary);
aryNew[1] = '紫霞仙子';
console.log(aryNew);
// ['齐天大圣孙悟空', '紫霞仙子', '沙悟净', '唐僧'] 新阵列资料已更改
console.log(ary);
// ['齐天大圣孙悟空', '猪八戒', '沙悟净', '唐僧'] 原阵列不受影响
let objNew = Object.assign({}, obj);
objNew.woman1 = '铁扇公主';
// {woman1: '铁扇公主', woman2: '紫霞仙子', man: '牛魔王'} 新物件资料更改
console.log(objNew);
// {woman1: '白骨精', woman2: '紫霞仙子', man: '牛魔王'} 原物件没有被更动
console.log(obj);
但目前我们做的都只是第一层的拷贝,底下我们来试试看在更深入的拷贝,结果会是如何。
let ary = [{woman1: '白骨精', woman2: '紫霞仙子', man: '牛魔王'}];
let aryNew = Object.assign([], ary);
aryNew[0].woman1 = '铁扇公主';
console.log(ary);
// {woman1: '铁扇公主', woman2: '紫霞仙子', man: '牛魔王'}
可以发现到了第二层,会直接更动原物件。
运算子展开的浅拷贝方式,是 ES6 新增的特性,主要是把一个阵列展开变成个别值,再放入指定的物件或阵列。
范例:
let ary = ['齐天大圣孙悟空', '猪八戒', '沙悟净', '唐僧'];
let obj = {woman1: '白骨精', woman2: '紫霞仙子', man: '牛魔王'};
let aryNew = [...ary];
aryNew[1] = '紫霞仙子';
console.log(aryNew);
// ['齐天大圣孙悟空', '紫霞仙子', '沙悟净', '唐僧'] 新阵列资料已更改
console.log(ary);
// ['齐天大圣孙悟空', '猪八戒', '沙悟净', '唐僧'] 原阵列不受影响
let objNew = {...obj};
objNew.woman1 = '铁扇公主';
// {woman1: '铁扇公主', woman2: '紫霞仙子', man: '牛魔王'} 新物件资料更改
console.log(objNew);
// {woman1: '白骨精', woman2: '紫霞仙子', man: '牛魔王'} 原物件没有被更动
console.log(obj);
这边到目前为止跟上面的范例是差不多的,不一样的地方只在於展开这个动作,而在第二层也同样会出现改变原物件的情况。
能深度复制同样的物件,但记忆体位置不同,两个为独立的记忆体空间,因此不会互相影响。
深拷贝也有两种方式:
JSON.stringify
,主要利用 JSON.stringify
把物件转成字串,再用 JSON.parse
把字串转为物件。这里稍微说明一下 JSON.stringify
和 JSON.parse
,JSON.stringify
为物件变 JSON 字串,JSON.parse
则是将 JSON 字串转物件。
JSON.stringify
范例:
let me = {name: 'Jemma'};
console.log(JSON.stringify(me)); // {"name":"Jemma"}
JSON.parse
范例:
let myName = JSON.parse('{"name":"Jemma"}');
console.log(myName); // {name: 'Jemma'}
稍微解释完 JSON.stringify
和 JSON.parse
,回归深拷贝的话题,刚刚说到深拷贝可以使用JSON.stringify
方法,我们一样直接来看范例:
let ary = [{woman1: '白骨精', woman2: '紫霞仙子', man: '牛魔王'}];
let aryNew = JSON.parse(JSON.stringify(ary));
aryNew[0].woman1 = '铁扇公主';
console.log(ary);
// {woman1: '白骨精', woman2: '紫霞仙子', man: '牛魔王'} 原资料没有被更动
console.log(aryNew);
// {woman1: '铁扇公主', woman2: '紫霞仙子', man: '牛魔王'}
可以看到这个范例,其实是拿示范浅拷贝第二层资料是否改变的那个范例,来做深拷贝示范,在浅拷贝的时候原资料确实被改变了,但在深拷贝的时候可以看到,aryNew 是一笔新的资料,因此不影响原本的 ary。
$.extend
在 jQuery 也提供一个深拷贝的方法,利用 $.extend
指定强制深拷贝,这里也稍微解释一下 $.extend
。
$.extend
/ 将两个或更多对象的内容合并到第一个对象。
语法:
jQuery.extend( [deep ], target, object1 [, objectN ] )
// deep 深拷贝
回到利用 $.extend
做深拷贝的范例,这里我一直无法 console 出来满满问号脸,为了避免花太多时间卡在这里,因此暂时先借用网路大神的范例:
let data = [
{
name: 'Eric',
weight: 60,
},
];
let dataCP = $.extend(true, [], data);
// 操作第一层 : 不影响原物件
dataCP.push({
name: 'Alice',
weight: 50,
});
// 操作第二层 : 不影响原物件
dataCP[0].name = 'Emma';
console.log(data); // [ { name: 'Eric', weight: 60 } ]
console.log(dataCP); // [ { name: 'Emma', weight: 60 }, { name: 'Alice', weight: 50 } ]
今天的文章就先分享到这,日後有研究出个什麽再补上了。
参考资料:
JavaScript 浅拷贝 (Shallow Copy) 与深拷贝 (Deep Copy)
资料型别 为何需判断型别,其因为电脑在执行时,需先判断资料是何种型别,才可采取运算方式。例如数字12...
说明、缘由 投入资讯产业约17年,历经过许多的程序语言,也投入过不同的行业别,5年前开始接触Odoo...
云解析(Alibaba Cloud DNS) 云解析是一个在阿里上的DNS托管工具,每个云端都有他自...
当我们的程序可能会有其他语言使用者时,就得开始考虑国际化的问题了,专业术语叫i18n: i n t ...
All life is an experiment. The more experiments y...