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 相关文章推荐
20个非常棒的 jQuery 幻灯片插件和教程分享
Aug 23 Javascript
当自定义数据属性为json格式字符串时jQuery的data api问题探讨
Feb 18 Javascript
iframe窗口高度自适应的又一个巧妙实现思路
Apr 04 Javascript
jQuery中on()方法用法实例
Jan 19 Javascript
使用Promise解决多层异步调用的简单学习心得
May 17 Javascript
jQuery过滤特殊字符及JS字符串转为数字
May 26 Javascript
基于cropper.js封装vue实现在线图片裁剪组件功能
Mar 01 Javascript
node.js部署之启动后台运行forever的方法
May 23 Javascript
JavaScript学习笔记之数组基本操作示例
Jan 09 Javascript
js设计模式之代理模式及订阅发布模式实例详解
Aug 15 Javascript
jQuery实现轮播图效果demo
Jan 11 jQuery
vue中data改变后让视图同步更新的方法
Mar 29 Vue.js
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
第七节 类的静态成员 [7]
2006/10/09 PHP
php后退一页表单内容保存实现方法
2012/06/17 PHP
叫你如何修改Nginx与PHP的文件上传大小限制
2014/09/10 PHP
PHP5多态性与动态绑定介绍
2015/04/03 PHP
Laravel实现构造函数自动依赖注入的方法
2016/03/16 PHP
yii通过小物件生成view的方法
2016/10/08 PHP
laravel框架中路由设置,路由参数和路由命名实例分析
2019/11/23 PHP
js动态生成指定行数的表格
2013/07/11 Javascript
jQuery简单实现banner图片切换
2014/01/02 Javascript
关于动态生成dom绑定事件失效的原因及解决方法
2016/08/06 Javascript
JavaScript职责链模式概述
2016/09/17 Javascript
浅谈angularjs module返回对象的坑(推荐)
2016/10/21 Javascript
解析预加载显示图片艺术
2016/12/05 Javascript
Bootstrap select下拉联动(jQuery cxselect)
2017/01/04 Javascript
老生常谈JavaScript面向对象基础与this指向问题
2017/10/16 Javascript
微信小程序实现图片上传功能实例(前端+PHP后端)
2018/01/10 Javascript
JavaScript错误处理操作实例详解
2019/01/04 Javascript
jQuery内容过滤选择器与子元素过滤选择器用法实例分析
2019/02/20 jQuery
微信小程序tabBar设置实例解析
2019/11/14 Javascript
ElementUI中el-tree节点的操作的实现
2020/02/27 Javascript
vue的$http的get请求要加上params操作
2020/11/12 Javascript
Python ljust rjust center输出
2008/09/06 Python
Python读写Json涉及到中文的处理方法
2016/09/12 Python
使用Numpy读取CSV文件,并进行行列删除的操作方法
2018/07/04 Python
PyQt5实现让QScrollArea支持鼠标拖动的操作方法
2019/06/19 Python
Tensorflow实现神经网络拟合线性回归
2019/07/19 Python
Pyqt5自适应布局实例
2019/12/13 Python
Python 在局部变量域中执行代码
2020/08/07 Python
Python自定义sorted排序实现方法详解
2020/09/18 Python
Django如何继承AbstractUser扩展字段
2020/11/27 Python
解决img标签上下出现间隙的方法
2016/12/14 HTML / CSS
网上常见的一份Linux面试题(多项选择部分)
2015/02/07 面试题
2014教师“四风问题”对照检查材料思想汇报
2014/09/16 职场文书
《有余数的除法》教学反思
2016/02/22 职场文书
商业计划书范文
2019/04/24 职场文书
python如何读取和存储dict()与.json格式文件
2022/06/25 Python