浅拷贝和深拷贝

来源:互联网 发布:为知笔记 开源 编辑:程序博客网 时间:2024/05/22 01:49

时间:2017年11月28日22:44:54

    对于程序员来说,编程语言就像是创作的工具,掌握扎实的语言功底才能创作出优秀的产品。世界上任何一门编程语言入门都很简单,但要掌握语言的核心和精髓是困难的,是需要循序渐进的,是需要不断的反复学习和实践的。

    在参加多次求职的面试过程中,遇到过同一个问题,实现对象浅拷贝和深拷贝函数。

    在明确要做的这件事情之前,要理解一下计算机存储的原理:对象的存储——指针指向内存地址,内存地址开辟的内存(空间)存储数据。(地址指针存储在 栈 中,数据存储在 堆 中)

    ES6中的object.assign(obj1,obj2,obj3)执行的是浅拷贝;

1、浅拷贝

    浅拷贝:新建一个指针,指向已有内存地址,新旧指针都能改变内存中的数据

    以数组为例,如下:

var arr = ['china','american','japan'];

var newArr = arr;

newArr[0] = 'zhongguo';

arr[1] = 'meiguo';

console.log(arr);//['zhongguo','meiguo','japan']

console.log(newArr);//['zhongguo','meiguo','japan']

    可以看到,改变新数组的元素内容,老数组的内容也变化了;改变老数组的元素内容,新数组的内容也变化了。由于var newArr = arr;这条语句执行的是一个 浅拷贝 操作,arr和newArr的指针都指向内存中的同一个地址。

    同样,对象的浅拷贝也是如此,如下:

var obj = {name:'wo',age:28,job:'programmer'};
var newObj = obj;
obj.name = 'me';
newObj.age = 'ershiba';
console.log(obj);//{name: "me", age: "ershiba", job: "programmer"}
console.log(newObj);//{name: "me", age: "ershiba", job: "programmer"}

2、深拷贝

    深拷贝:新建一个指针和内存,新的指针指向新的内存(老指针指向老内存)

    以数组为例,如下:

    一维数组的 深拷贝:

var arr = ['china','american','japan'];
var newArr = [];
for(var item in arr){
newArr[item] = arr[item];
}
console.log(arr);//["china", "american", "japan"]
console.log(newArr);//["china", "american", "japan"]
arr[0] = 'zhongguo';
newArr[1] = 'meiguo';
console.log(arr);//["zhongguo", "american", "japan"]
console.log(newArr);//["china", "meiguo", "japan"]

    二维及多维数组的 深拷贝:

var arr = ['china','american','japan',['you','me','he']];
function deepCopy(arr){
var newArr = [];
for(var item in arr){
newArr[item] = arr[item] instanceof Array ? deepCopy(arr[item]) : arr[item];
}
return newArr;
}
var newArr = deepCopy(arr);
console.log(arr);//['china','american','japan',['you','me','he']]
console.log(newArr);//['china','american','japan',['you','me','he']]
arr[0] = 'zhongguo';
newArr[3][0] = 'ni';
console.log(arr);//['zhongguo','american','japan',['you','me','he']]
console.log(newArr);//['china','american','japan',['ni','me','he']]

    可以看到,改变新数组的元素内容,老数组的内容不发生变化;改变老数组的元素内容,新数组的内容也不会发生变化。由于newArr[item] = arr[item];这条语句执行的是一个 深拷贝 操作,arr和newArr的指针分别指向内存中不同的地址。

    同样,对象的 深拷贝 也是如此,如下:

    一维对象的 深拷贝:

var obj = {name:'wo',age:28,job:'programmer'};
var newObj = {};
for(var item in obj){
newObj[item] = obj[item];
}
console.log(obj);//{name:'wo',age:28,job:'programmer'}
console.log(newObj);//{name:'wo',age:28,job:'programmer'}
obj.name = 'me';
newObj.age = 'ershiba';
console.log(obj);//{name:'me',age:28,job:'programmer'}
console.log(newObj);//{name:'wo',age:'ershiba',job:'programmer'}

    二维及多维对象的 深拷贝:

var obj = {name:'wo',age:28,job:'programmer',localtion:{city:'beijing',subway:{color:'red',speed:100}}};
function deepCopy(obj){
var newObj = {};
for(var item in obj){
newObj[item] = typeof obj[item] === 'object' ? deepCopy(obj[item]) : obj[item];
}
return newObj;
}
var newObj = deepCopy(obj);
console.log(obj);

//{name:'wo',age:28,job:'programmer',localtion:{city:'beijing',subway:{color:'red',speed:100}}}
console.log(newObj);

//{name:'wo',age:28,job:'programmer',localtion:{city:'beijing',subway:{color:'red',speed:100}}}
obj.name = 'me';
newObj.localtion.subway.color = 'green';
console.log(obj);

//{name:'me',age:28,job:'programmer',localtion:{city:'beijing',subway:{color:'red',speed:100}}}
console.log(newObj);

//{name:'wo',age:28,job:'programmer',localtion:{city:'beijing',subway:{color:'green',speed:100}}}

3、jQuery深拷贝

    .clone()创建一个匹配的元素集合的深度拷贝副本;

    DOM结构如下:

<div class="container">
  <div class="hello">Hello</div>
  <div class="goodbye">Goodbye</div>
</div>

    移动DOM元素的操作,$('.hello').appendTo('.goodbye'),得到的DOM结构如下:
<div class="container">
  <div class="goodbye">
    Goodbye
    <div class="hello">Hello</div>
  </div>
</div>

    复制DOM元素的操作,$('.hello').clone().appendTo('.goodbye'),得到的DOM结构如下:
<div class="container">
  <div class="hello">Hello</div>
  <div class="goodbye">
    Goodbye
    <div class="hello">Hello</div>
  </div>
</div>

注意:当我们用.clone()方法时,在将它插入到文档之前,我们可以修改克隆后的元素或者元素内容。

4、ES6语法的对象合并

    Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target):

const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

注意:Object.assign方法实行的是浅拷贝,而不是深拷贝。如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

5、案例

案例一:

    通过请求接口获取数据,需要存储两份数据到redux中,一份数据当做静态数据,一份当做动态数据,如下操作:

saveDynamic(data);

saveStatic(data);

    这样操作的结果,动态和静态数据的地址指针指向同一个地址,属于浅拷贝,因此,需要做如下操作:

saveDynamic(data);

saveStatic(JSON.parse(JSON.stringify(data)));

    如上,经过JSON的编码和解码,动态和静态数据存储的指针指向了不同的地址;


未完,待续。。。


0 0
原创粉丝点击