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 相关文章推荐
checkbox 多选框 联动实现代码
Oct 22 Javascript
javascript 密码强弱度检测万能插件
Feb 25 Javascript
Extjs学习笔记之二 初识Extjs之Form
Jan 07 Javascript
jquery简单倒计时实现方法
Dec 18 Javascript
使用bootstrap实现多窗口和拖动效果
Sep 22 Javascript
jQuery插件HighCharts实现气泡图效果示例【附demo源码】
Mar 13 Javascript
JavaScript 有用的代码片段和 trick
Feb 22 Javascript
使用vue点击li,获取当前点击li父辈元素的属性值方法
Sep 12 Javascript
微信小程序开发之转发分享功能
Oct 22 Javascript
基于JavaScript伪随机正态分布代码实例
Nov 07 Javascript
JS的时间格式化和时间戳转换函数示例详解
Jul 27 Javascript
Axios取消重复请求的方法实例详解
Jun 15 Javascript
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
解析左右值无限分类的实现算法
2013/06/20 PHP
怎么在Windows系统中搭建php环境
2013/08/31 PHP
php使用array_search函数实现数组查找的方法
2015/06/12 PHP
分享五个PHP7性能优化提升技巧
2015/12/07 PHP
通过PHP简单实例介绍文件上传
2015/12/16 PHP
详解WordPress中分类函数wp_list_categories的使用
2016/01/04 PHP
关于window.pageYOffset和document.documentElement.scrollTop
2011/04/05 Javascript
jquery实现将获取的颜色值转换为十六进制形式的方法
2014/12/20 Javascript
javascript实现dom动态创建省市纵向列表菜单的方法
2015/05/14 Javascript
很不错的两款Bootstrap Icon图标选择组件
2016/01/28 Javascript
你真的了解BOM中的history对象吗
2017/02/13 Javascript
关于bootstrap日期转化,bootstrap-editable的简单使用,bootstrap-fileinput的使用详解
2017/05/12 Javascript
Linux Centos7.2下安装nodejs&amp;npm配置全局路径的教程
2018/05/15 NodeJs
vue设置动态请求地址的例子
2019/11/01 Javascript
Python迭代用法实例教程
2014/09/08 Python
Python的Django框架中的select_related函数对QuerySet 查询的优化
2015/04/01 Python
python中range()与xrange()用法分析
2016/09/21 Python
Python网络编程 Python套接字编程
2017/09/13 Python
Python 实现在文件中的每一行添加一个逗号
2018/04/29 Python
使用Python监视指定目录下文件变更的方法
2018/10/15 Python
使用CodeMirror实现Python3在线编辑器的示例代码
2019/01/14 Python
对Python _取log的几种方式小结
2019/07/25 Python
基于python+selenium自动健康打卡的实现代码
2021/01/13 Python
python中numpy数组与list相互转换实例方法
2021/01/29 Python
Canvas在超级玛丽游戏中的应用详解
2021/02/06 HTML / CSS
波兰多品牌运动商店:StreetStyle24.pl
2020/09/22 全球购物
什么叫应用程序域?什么是受管制的代码?什么是强类型系统?什么是装箱和拆箱?
2016/08/13 面试题
UNIX特点都有哪些
2016/04/05 面试题
竞争性谈判邀请书
2014/02/06 职场文书
十八届三中全会学习方案
2014/02/16 职场文书
白血病募捐倡议书
2014/05/14 职场文书
学校火灾防控方案
2014/06/09 职场文书
高中生打架检讨书1000字
2015/02/17 职场文书
十月围城观后感
2015/06/08 职场文书
课文《燕子》教学反思
2016/02/17 职场文书
Grafana可视化监控系统结合SpringBoot使用
2022/04/19 Redis