js 实现拷贝

浅拷贝

    浅拷贝只会被拷贝最外边的一层,即只拷贝指针而不拷贝内容。

    实现浅拷贝的方式有:

1、Object.assign

var obj = {
    a: 1,
    b: {
        c: 1
    }
}
var objCopy = Object.assign({},obj);
console.log(obj === objCopy)  // 输出 false
console.log(obj.b === objCopy.b)  // 输出 true
objCopy.b.c = 2; 
console.log(obj.b.c)  // 输出2  obj的内容发生改变
2、$.extend
var obj = {
    a: 1,
    b: {
        c: 1
    }
}
var objCopy = $.extend(false,{},obj);
console.log(obj === objCopy)  // 输出 false
console.log(obj.b === objCopy.b)  // 输出 true
objCopy.b.c = 2; 
console.log(obj.b.c)  // 输出2  obj的内容发生改变

3、简单复制

function copy(src) {
    if (typeof src !== 'object') {
        return src;
    }
    var dest = {};
    for(var p in src) {
        if (Object.prototype.toString.call(src[p]) ==='[object RegExp]') {
	    var exp = new RegExp(src[p].source,src[p].flags)
	    dest[p] = exp;
	} else {
	    dest[p] = src[p];
	}
    }
    return dest;
}

深拷贝

深拷贝会被拷贝全部内容,拷贝对象的改变不会影响被拷贝的对象。

实现深拷贝的方式有:

1、$.extend

var obj = {
    a: 1,
    b: {
        c: 1
    }
}
var objCopy = $.extend(true,{},obj);
console.log(obj === objCopy)  // 输出 false
console.log(obj.b === objCopy.b)  // 输出 false
objCopy.b.c = 2; 
console.log(obj.b.c)  // 输出1  obj的内容未发生改变

$.extend方式实现深拷贝,并未拷贝被拷贝对象的__proto__ ,而是把__proto__ 重置成了Object.prototype。

function Obj() {
    this.name = "tom";
    this.age = 18;
}
Obj.prototype.say = function() {
    console.log("hello");
}
var obj = new Obj();
var objCopy = $.extend(true,{},obj);
console.log(obj.__proto__ === Obj.prototype)  // 输出true
console.log(objCopy.__proto__ === Obj.prototype)  // 输出false
console.log(obj.__proto__ === Object.prototype) // 输出false
console.log(objCopy.__proto__ === Object.prototype) // 输出true

若遇到两个相互引用的对象会出现死循环。

var obj = {
    a: 1,
    b: {
	c: 1
    }
}
var objCopy = {}
objCopy.a = obj;
obj.d = objCopy;
var s = $.extend(true,{},obj); // Uncaught RangeError: Maximum call stack size exceeded

2、序列号与反序列化(JSON.stringify和JSON.parse)

var obj = {
    a: 1,
    b: {
        c: 1
    }
}
var objCopy = JSON.parse(JSON.stringify(obj))
console.log(obj === objCopy)  // 输出 false
console.log(obj.b === objCopy.b)  // 输出 false
objCopy.b.c = 2; 
console.log(obj.b.c)  // 输出1  obj的内容未发生改变
var dd = {}
dd.a = obj;
obj.d = dd;
JSON.stringify(obj);  //Uncaught TypeError: Converting circular structure to JSON

这种方式比较简单实用,但是如何被拷贝的对象包含函数、RegExp对象等不能被转化为json格式的对象,就不适用了。与$.extend相同若遇到两个相互引用的对象会抛出异常。

3、递归拷贝

function copy(isDeep,src) {
    if (typeof src !== 'object') {
        return src;
    }
    var dest = {};
    for(var p in src) {
        if (Object.prototype.toString.call(src[p]) ==='[object RegExp]') {
            var exp = new RegExp(src[p].source,src[p].flags)
            dest[p] = exp;
        } else {
            if (typeof src[p] === 'object' && isDeep) {
                dest[p] = copy(isDeep,src[p]);
            } else {
                dest[p] = src[p];
            }
        }
    }
    return dest;
}
var obj = {
    a: 1,
    b: {
        c: 1
    }
}
var objCopy =copy(true, obj)
console.log(obj === objCopy)  // 输出 false
console.log(obj.b === objCopy.b)  // 输出 false
objCopy.b.c = 2; 
console.log(obj.b.c)  // 输出1  obj的内容未发生改变

这种方式可以实现深拷贝,但是当被拷贝对象有不可枚举属性(enumerable: false)时,则该属性不会拷贝。若遇到两个相互引用的对象会抛出异常。

两个对象相互引用的情况,正常情况基本不会出现,所以可不考虑这种情况。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值