Libx

JS深浅拷贝

Word count: 760Reading time: 4 min
2017/09/04 Share

对JS的深浅拷贝比较常用的方法来做一下总结。

代码来说话

举个例子就差不多能懂这两个东西是什么了:

let me ={
'name':'xiaoming',
'age':'18',
'girlFriend':null,
'skill':{
'eat':true
'sleep':true,
'hitBeans':true
}
}

这是一个比较典型一点的对象,现在然后来做一下测试:

function shallowCopy(src) {
let dst = {};
for (let prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
}
function deepCopy(src){
let dist = {}
let keys = Object.keys(src),
temp = null,
key = null,
leng = keys.length
for(let i = 0;i<length;i++){
key = keys[i]
temp = src[key]
if(temp && typeof temp==='Object'){
dist[key] = deepCopy(temp)
}else{
dist[key]=temp
}
}
}
let he = me;
let she = shallowCopy(me);
let emm = deepCopy(me)

来分别进行几个简单的操作:

1 he.name = "xiaogang";
2 she.age = "20";
3 she.skill.eat= false
4 emm.skill.eat = false

  • he只是me的一个引用,也就是会改变me的值:

    me.name === xiaogang //true
  • she是一层浅拷贝,she.age = 20 此时she的age是新开辟的内存,so

    me.age=== 18 //true
  • she.skill.eat 涉及到了me的一个对象属性skill而上面的一个浅拷贝方法并没有进行递归的操作,只是将第一层的属性复制一遍,而skill对象依然是保存的一个引用,所以就很明显了。

    me.skill.eat === false //true
  • emm.skill.eat emm就是深拷贝得来的了,skill对象均是新开辟内存,所以就很明显了。

    me.skill.eat === false //false

突然觉得命名有些不合适。。怪怪的。。

浅拷贝

这里总结一下常见的几种浅拷贝的方法:

  • 直接遍历一遍

    function shallowCopy(src) {
    let dst = {};
    for (let prop in src) {
    if (src.hasOwnProperty(prop)) {
    dst[prop] = src[prop];
    }
    }
    return dst;
    }
  • 使用 Object.assign(),其会拷贝源对象自身且可枚举的属性到目标对象

    const obj = {xxxxx}
    const copyObj = Object.assign({},obj)

深拷贝

  • 我万万没有想到的是,JSON.stringfy(),和JSON.parse()竟然是最简单且执行效率最高的方法??
function deepCopy(obj){
const dist = JSON.parse(JSON.stringfy(obj))
return dist
}
  • 正常点的方法(适用于纯对象)
    function deepCopy(src){
    let dist = {}
    let keys = Object.keys(src),
    temp = null,
    key = null,
    leng = keys.length
    for(let i = 0;i<length;i++){
    key = keys[i]
    temp = src[key]
    if(temp && typeof temp==='Object'){
    dist[key] = deepCopy(temp)
    }else{
    dist[key]=temp
    }
    }
    }

在实际使用时,其实还是要注意Array,Date,RegExp的处理。。这里祭出一段Zepto的源码实现

/* 内部方法:用户合并一个或多个对象到第一个对象
* target 目标对象 对象都合并到target里
* source 合并对象
* deep 是否执行深度合并
*/
function extend(target, source, deep) {
for (key in source)
if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
if (isPlainObject(source[key]) && !isPlainObject(target[key]))
target[key] = {}
if (isArray(source[key]) && !isArray(target[key]))
target[key] = []
// 递归
extend(target[key], source[key], deep)
}
else if (source[key] !== undefined) target[key] = source[key]
}
// Copy all but undefined properties from one or more
// objects to the `target` object.
$.extend = function(target){
var deep, args = slice.call(arguments, 1);
//第一个参数为boolean值时,表示是否深度合并
if (typeof target == 'boolean') {
deep = target;
//target取第二个参数
target = args.shift()
}
// 遍历后面的参数,都合并到target上
args.forEach(function(arg){ extend(target, arg, deep) })
return target
}

以及各种奇淫巧技https://dassur/.ma/things/deep-copy

CATALOG
  1. 1. 代码来说话
  2. 2. 浅拷贝
  3. 3. 深拷贝