javascript深拷贝和浅拷贝详解


Posted in Javascript onFebruary 14, 2017

一、数组的深浅拷贝

在使用JavaScript对数组进行操作的时候,我们经常需要将数组进行备份,事实证明如果只是简单的将它赋予其他变量,那么我们只要更改其中的任何一个,然后其他的也会跟着改变,这就导致了问题的发生。

这是为什么呢?

因为如果只是简单的赋值,它只是进行了地址的引用,所以改变一个另一个也会跟着变。

var arr = ["One","Two","Three"];
var arrto = arr;
arrto[1] = "test";
document.writeln("数组的原始值:" + arr + "<br />");//Export:数组的原始值:One,test,Three
document.writeln("数组的新值:" + arrto + "<br />");//Export:数组的新值:One,test,Three

像上面这样就属于浅拷贝,那我们怎么样才能不改变原始的呢?

方法一:js的slice函数

var arr = ["One","Two","Three"];
var arrtoo = arr.slice(0);
arrtoo[1] = "set Map";
document.writeln("数组的原始值:" + arr + "<br />");//Export:数组的原始值:One,Two,Three
document.writeln("数组的新值:" + arrtoo + "<br />");//Export:数组的新值:One,set Map,Three

方法二:js的concat方法

concat() 方法用于连接两个或多个数组。

该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。

var arr = ["One","Two","Three"];
var arrtooo = arr.concat();
arrtooo[1] = "set Map To";
document.writeln("数组的原始值:" + arr + "<br />");//Export:数组的原始值:One,Two,Three
document.writeln("数组的新值:" + arrtooo + "<br />");//Export:数组的新值:One,set Map To,Three

二、对象的深浅拷贝

var a={name:'yy',age:26};
var b=new Object();
b.name=a.name;
b.age=a.age;
a.name='xx';
console.log(b);//Object { name="yy", age=26}
console.log(a);//Object { name="xx", age=26}

或者

var deepCopy= function(source) {
 var result={};
 for (var key in source) {
  result[key] = typeof source[key]==='object'? deepCoyp(source[key]): source[key];
 } 
 return result; 
}

object()方法:json格式的发明人Douglas Crockford,提出了一个object()函数,可以做到这一点。

function object(o) {

function F() {}


F.prototype = o;


return new F();

}
//这个object()函数,其实只做一件事,就是把子对象的prototype属性,指向父对象,从而使得子对象与父对象连在一起。

使用的时候,第一步先在父对象的基础上,生成子对象:

var Doctor = object(Chinese);
//然后,再加上子对象本身的属性:
Doctor.career = '医生';
//这时,子对象已经继承了父对象的属性了。
alert(Doctor.nation); //中国

下面我们看看阮一峰的方法

比如,现在有一个对象,叫做"中国人"。

var Chinese = {


nation:'中国'

};

还有一个对象,叫做"医生"。

var Doctor ={


career:'医生'

}

请问怎样才能让"医生"去继承"中国人",也就是说,我怎样才能生成一个"中国医生"的对象?

三、浅拷贝

除了使用"prototype链"以外,还有另一种思路:把父对象的属性,全部拷贝给子对象,也能实现继承。

下面这个函数,就是在做拷贝:

function extendCopy(p) {


var c = {};


for (var i in p) { 



c[i] = p[i];


}


c.uber = p;


return c;

}

使用的时候,这样写:

var Doctor = extendCopy(Chinese);

Doctor.career = '医生';

alert(Doctor.nation); // 中国

但是,这样的拷贝有一个问题。那就是,如果父对象的属性等于数组或另一个对象,那么实际上,子对象获得的只是一个内存地址,而不是真正拷贝,因此存在父对象被篡改的可能。

请看,现在给Chinese添加一个"出生地"属性,它的值是一个数组。

Chinese.birthPlaces = ['北京','上海','香港'];

通过extendCopy()函数,Doctor继承了Chinese。

var Doctor = extendCopy(Chinese);

然后,我们为Doctor的"出生地"添加一个城市:

Doctor.birthPlaces.push('厦门');

发生了什么事?Chinese的"出生地"也被改掉了!

alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
alert(Chinese.birthPlaces); //北京, 上海, 香港, 厦门

所以,extendCopy()只是拷贝基本类型的数据,我们把这种拷贝叫做"浅拷贝"。这是早期jQuery实现继承的方式。

四、深拷贝

所谓"深拷贝",就是能够实现真正意义上的数组和对象的拷贝。它的实现并不难,只要递归调用"浅拷贝"就行了。

function deepCopy(p, c) {


var c = c || {};


for (var i in p) {



if (typeof p[i] === 'object') {




c[i] = (p[i].constructor === Array) ? [] : {};




deepCopy(p[i], c[i]);



} else {




 c[i] = p[i];



}


}


return c;

}

使用的时候这样写:

var Doctor = deepCopy(Chinese);

现在,给父对象加一个属性,值为数组。然后,在子对象上修改这个属性:

Chinese.birthPlaces = ['北京','上海','香港'];

Doctor.birthPlaces.push('厦门');

这时,父对象就不会受到影响了。

alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门

alert(Chinese.birthPlaces); //北京, 上海, 香港

目前,jQuery库使用的就是这种继承方法。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
Prototype 学习 工具函数学习($A方法)
Jul 12 Javascript
细说浏览器特性检测(2)-通用事件检测
Nov 05 Javascript
javascript 树形导航菜单实例代码
Aug 13 Javascript
js获取多个tagname的节点数组
Sep 22 Javascript
javascript实现节点(div)名称编辑
Dec 17 Javascript
javascript实现页面刷新时自动清空表单并选中的方法
Jul 18 Javascript
JS禁止查看网页源代码的实现方法
Oct 12 Javascript
Javascript使用uploadify来实现多文件上传
Nov 16 Javascript
关于vue中的ajax请求和axios包问题
Apr 19 Javascript
基于Vue实现拖拽效果
Apr 27 Javascript
AngularJS 监听变量变化的实现方法
Oct 09 Javascript
jQuery实现广告显示和隐藏动画
Jul 04 jQuery
javascript事件的传播基础实例讲解(35)
Feb 14 #Javascript
微信小程序中实现一对多发消息详解及实例代码
Feb 14 #Javascript
有关JS中的0,null,undefined,[],{},'''''''',false之间的关系
Feb 14 #Javascript
js基于myFocus实现轮播图效果
Feb 14 #Javascript
javascript 单例模式详解及简单实例
Feb 14 #Javascript
bootstrap 下拉多选框进行多选传值问题代码分析
Feb 14 #Javascript
微信小程序 弹幕功能简单实例
Feb 14 #Javascript
You might like
优化PHP程序的方法小结
2012/02/23 PHP
php编程每天必学之表单验证
2016/03/01 PHP
php无法连接mysql数据库的正确解决方法
2016/07/01 PHP
TP5框架实现的数据库备份功能示例
2020/04/05 PHP
使用JavaScript 编写简单计算器
2014/11/24 Javascript
Javascript前端UI框架Kit使用指南之kitjs事件管理
2014/11/28 Javascript
如何利用JS通过身份证号获取当事人的生日、年龄、性别
2016/01/22 Javascript
JS简单实现DIV相对于浏览器固定位置不变的方法
2016/06/17 Javascript
简单实现jQuery弹幕效果
2017/05/06 jQuery
node.js文件上传重命名以及移动位置的示例代码
2018/01/19 Javascript
Vue组件和Route的生命周期实例详解
2018/02/10 Javascript
详解ES6通过WeakMap解决内存泄漏问题
2018/03/09 Javascript
微信小程序之swiper滑动面板用法示例
2018/12/04 Javascript
vue+Vue Router多级侧导航切换路由(页面)的实现代码
2018/12/20 Javascript
微信小程序实现复选框效果
2018/12/28 Javascript
实用Javascript调试技巧分享(小结)
2019/06/18 Javascript
Vue.js标签页组件使用方法详解
2019/10/19 Javascript
JQuery 实现文件下载的常用方法分析
2019/10/29 jQuery
angularjs模态框的使用代码实例
2019/12/20 Javascript
[05:10]2014DOTA2国际邀请赛 通往胜利之匙赛场探秘之旅
2014/07/18 DOTA
Python下线程之间的共享和释放示例
2015/05/04 Python
python生成密码字典的方法
2018/07/06 Python
在python中使用with打开多个文件的方法
2019/01/07 Python
基于wxPython的GUI实现输入对话框(1)
2019/02/27 Python
python实现超市商品销售管理系统
2019/11/22 Python
Keras自定义IOU方式
2020/06/10 Python
Python datetime模块使用方法小结
2020/06/18 Python
Django web自定义通用权限控制实现方法
2020/11/24 Python
使用CSS3的appearance属性改变元素的外观的方法
2015/12/12 HTML / CSS
党的群众路线教育实践方案
2014/05/11 职场文书
公司副总经理岗位职责
2014/10/01 职场文书
个人整改措施落实情况汇报
2014/10/29 职场文书
2015年医药代表工作总结
2015/04/25 职场文书
幼儿园中班教育随笔
2015/08/14 职场文书
反四风问题学习心得体会
2016/01/22 职场文书
pytorch 运行一段时间后出现GPU OOM的问题
2021/06/02 Python