最近更新时间: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的DOM深拷贝
.clone()创建一个匹配的元素集合的深度拷贝副本;
DOM结构如下:
移动DOM元素的操作,$('.hello').appendTo('.goodbye'),得到的DOM结构如下:
Goodbye
复制DOM元素的操作,$('.hello').clone().appendTo('.goodbye'),得到的DOM结构如下:
Goodbye
注意:当我们用.clone()方法时,在将它插入到文档之前,我们可以修改克隆后的元素或者元素内容。
5、jQuery的对象拷贝
参考我的文章《jQuery学习使用和源码解读》
6、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方法实行的是浅拷贝,而不是深拷贝。如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。
7、深拷贝案例
方案一,JSON数据格式-转码和解码:
通过请求接口获取数据,需要存储两份数据到redux中,一份数据当做静态数据,一份当做动态数据,如下操作:
saveDynamic(data);
saveStatic(data);
这样操作的结果,动态和静态数据的地址指针指向同一个地址,属于浅拷贝,因此,需要做如下操作:
saveDynamic(data);
saveStatic(JSON.parse(JSON.stringify(data)));
如上,经过JSON的编码和解码,动态和静态数据存储的指针指向了不同的地址;
方案二,es6新语法-扩展运算符...:
let data = this.props.qaData;//[]这是一个数组
let newData = [...data,{data:item.questions,position:'left',type:'array'}];//扩展运算符
newData的地址和data的地址不一样了
未完,待续。。。