js中的深拷贝和浅拷贝2
2024-09-06 12:28:44
所谓 深浅拷贝:
对于仅仅是复制了引用(地址),换句话说,复制了之后,原来的变量和新的变量指向同一个东西,彼此之间的操作会互相影响,为 浅拷贝。
而如果是在堆中重新分配内存,拥有不同的地址,但是值是一样的,复制后的对象与原来的对象是完全隔离,互不影响,为 深拷贝。
深浅拷贝 的主要区别就是:复制的是引用(地址)还是复制的是实例。
//浅复制
function shallowCopy(src){
var dst = {};
for(var key in src){
if(src.hasOwnProperty(key)){
dst[key] = src[key];
}
}
return dst;
} var obj = {
a : 1,
arr : [2,3]
};
var shallowObj = shallowCopy(obj);
console.log(obj === shallowObj); //false
shallowObj.arr[1] = 5;
console.log(obj.arr[1]); // = 5
console.log(obj); //{ a: 1, arr: [ 2, 5 ] }
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: '深圳' } }
最新文章
- 【转】缺少servlet-api.jar包
- 为控件Button设置快捷键(组合键)
- ApiDoc 文档使用方式
- LoadRunner之自定义HTTP请求
- oracle—无法启动
- java核心技术记录之集合
- 2014--9=17 软工二班 MyEclipse blue==3
- 【Android】Android实现截取当前屏幕图片并保存至SDCard
- MapReduce的C#实现及单元测试(试验)
- ie8下下拉菜单文字为空
- hibernate第二天
- Redis Cluster的搭建与部署,实现redis的分布式方案
- Bootstrap3 栅格系统-列偏移
- matplotlib箱线图与柱状图比较
- ttribute ";xmlns"; was already specified for element ";web-app";.
- ubuntu 常见命令整理
- Linux系统运维故障排查
- Quartz Trigger Priority 触发器优先级
- JavaScript位运算符
- LeanCloud
热门文章
- {Django基础七之Ajax} 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解)
- Python运算符,逻辑运算
- Ubuntu中使用Nginx+rtmp搭建流媒体直播服务
- Spring Cloud Eureka 使用外网IP和端口号进行服务注册
- 如何使用Junit进行单元测试
- linux平台进行c语言源码安装
- R语言建立回归分析,并利用VIF查看共线性问题的例子
- 转:Linux fork与vfork的深入分析
- JMETER远程运行_多机联合负载
- jmeter体系结构