js中的深拷贝和浅拷贝2

所谓 深浅拷贝
对于仅仅是复制了引用(地址),换句话说,复制了之后,原来的变量和新的变量指向同一个东西,彼此之间的操作会互相影响,为 浅拷贝
而如果是在堆中重新分配内存,拥有不同的地址,但是值是一样的,复制后的对象与原来的对象是完全隔离,互不影响,为 深拷贝
 
深浅拷贝 的主要区别就是:复制的是引用(地址)还是复制的是实例。
 1 //浅复制
 2 function shallowCopy(src){
 3     var dst = {};
 4     for(var key in src){
 5         if(src.hasOwnProperty(key)){
 6             dst[key] = src[key];
 7         }
 8     }
 9     return dst;
10 }
11 
12 var obj = {
13     a : 1,
14     arr : [2,3]
15 };
16 var shallowObj = shallowCopy(obj);
17 console.log(obj === shallowObj);   //false
18 shallowObj.arr[1] = 5;
19 console.log(obj.arr[1]);   // = 5
20 console.log(obj);         //{ a: 1, arr: [ 2, 5 ] }
21 console.log(shallowObj);  //{ a: 1, arr: [ 2, 5 ] }
//利用 递归 来实现深复制,对属性中所有引用类型的值,遍历到是基本类型的值为止。
function deepCopy(src){
    if(!src && typeof src !== 'object'){
        return;
    }
    var dst = src.constructor  === Array ? []:{};
    for(var key in src){
        if(src.hasOwnProperty(key)){
            if(src[key] && typeof src[key] === 'object'){
                dst[key] = src[key].constructor === Array ? []:{};
                dst[key] = deepCopy(src[key]);   //递归
            }else{
                dst[key] = src[key];
            }
        }
    }
    return dst;
}


var a = {
    name:"jack",
    age:20
};
var b = deepCopy(a);
console.log(a === b);   //false
a.age = 30;
console.log(a);     //{ name: 'jack', age: 30 }
console.log(b);     //{ name: 'jack', age: 20 }

 深拷贝浅拷贝问题探究:

1. Array 的 slice 和 concat 方法

两者都会返回一个新的数组实例。

//slice
var a = [1,2,3];
var b = a.slice(); //slice
    console.log(b === a);
a[0] = 4;
    console.log(a); //[ 4, 2, 3 ]
    console.log(b); //[ 1, 2, 3 ]

//concat
var a = [1,2,3];
var b = a.concat();  //concat
    console.log(b === a);
a[0] = 4;
    console.log(a);  //[ 4, 2, 3 ]
    console.log(b);  //[ 1, 2, 3 ]

看起来很像深拷贝,但实际上不是!!!

//slice
var a = [[1,2,3],4,5];
var b = a.slice();
    console.log(a === b); //false
a[0][0] = 6;
    console.log(a);   //[ [ 6, 2, 3 ], 4, 5 ]
    console.log(b);   //[ [ 6, 2, 3 ], 4, 5 ]

//concat
var a = [[1,2,3],4,5];
var b = a.concat();  //concat
    console.log(b === a); //false
a[0][0] = 6;
    console.log(a);  //[ [ 6, 2, 3 ], 4, 5 ]
    console.log(b);  //[ [ 6, 2, 3 ], 4, 5 ]

 Array的 slice 和 concat 方法 并不是 真正的深拷贝,他们其实是浅拷贝。   递归复制是无法完成的。

2. jQuery中的 extend 复制方法

可以用来扩展对象,这个方法可以传入一个参数:deep(true or false),表示是否执行深复制(如果是深复制则会执行递归复制)。

//jQuery环境下运行
//深复制
var
obj = { name:'xixi', age:20, company : { name : '腾讯', address : '深圳'} }; var obj_extend = $.extend(true,{}, obj); //extend方法,第一个参数为true,为深拷贝,为false,或者没有为浅拷贝。 console.log(obj === obj_extend); //false obj.company.name = "ali"; obj.name = "hei"; console.log(obj); //{name:'hei',age:20,company : { name : 'ali', address : '深圳'} } console.log(obj_extend); //{name:'xixi',age:20,company : { name : '腾讯', address : '深圳'} }

//jQuery环境下运行
//浅复制
var obj = {
    name:"xixi",
    age:20,
    company : { name : '腾讯', address : '深圳'} 
};
var obj_extend = $.extend(false,{}, obj); //extend方法,第一个参数为true,为深拷贝,为false,或者没有为浅拷贝。
console.log(obj === obj_extend);   //false
obj.name = "heihei";
console.log(obj);    //{name:'heihei',age:20,company : { name : '腾讯', address : '深圳'} 
console.log(obj_extend);  //{name:'xixi',age:20,company : { name : '腾讯', address : '深圳'} 

总结:Array 的 slice 和 concat 方法 和 jQuery 中的 extend 复制方法,他们都会复制第一层的值,对于 第一层 的值都是 深拷贝,而到 第二层 的时候 Array 的 slice 和 concat 方法就是 复制引用 ,jQuery 中的 extend 复制方法 则 取决于 你的 第一个参数, 也就是是否进行递归复制。所谓第一层 就是 key 所对应的 value 值是基本数据类型,也就像上面栗子中的name、age,而对于 value 值是引用类型 则为第二层,也就像上面例子中的 company。

3. JSON 对象的 parse 和 stringify

JOSN 对象中的 stringify 可以把一个 js 对象序列化为一个 JSON 字符串,parse 可以把 JSON 字符串反序列化为一个 js 对象,这两个方法实现的是深拷贝

var obj = {
    name:'xixi',
    age:20,
    company : { name : '腾讯', address : '深圳'} 
};
var obj_json = JSON.parse(JSON.stringify(obj));
console.log(obj === obj_json);   //false
obj.company.name = "ali";
obj.name = "hei";
console.log(obj);   //{ name: 'hei', age: 20, company: { name: 'ali', address: '深圳' } }
console.log(obj_json);  //{ name: 'xixi', age: 20, company: { name: '腾讯', address: '深圳' } }

 

posted @ 2017-07-08 18:46  gq_orange  阅读(247)  评论(0编辑  收藏  举报