数组和对象的浅拷贝,深拷贝

在说数组和对象的浅拷贝,深拷贝的问题前我们先了解一下javaScript的变量类型。
(1)基本类型:
5种基本数据类型Undefined、Null、Boolean、Number 和 String,变量是直接按值存放的,存放在栈内存中的简单数据段,可以直接访问。

(2)引用类型:
存放在堆内存中的对象,变量保存的是一个指针,这个指针指向另一个位置。当需要访问引用类型(如对象,数组等)的值时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。

JavaScript存储对象都是存地址的,所以浅拷贝会导致 obj1 和obj2 指向同一块内存地址。
改变了其中一方的内容,都是在原来的内存上做修改会导致拷贝对象和源对象都发生改变,
而深拷贝是开辟一块新的内存地址,将原对象的各个属性逐个复制进去。
对拷贝对象和源对象各自的操作互不影响。

先看下下边例子:

var a = 10;
var b = a;
b = 20;
console.log(a);//10
console.log(b);//20

上边代码在修改b的值时并不会改到a。

但是对象和数组就不一样了,对象和数组是按引用传值,具体如下:

//浅拷贝,双向改变,指向同一片内存空间
var obj = {'age':20}
var newobj = obj
newobj.age= 30
console.log(obj.age); //30
console.log(newobj.age); // 30

上边的代码在修改新对象newobj的age值,原来的对象obj的age值也改变了,为什么呢?因为对象和数组是按引用传值,所以他们根本是同一个对象,上面代码中,newobj 并不是obj 的克隆,而是指向同一份数据的另一个指针。修改newobj ,会直接导致obj 的变化。这就是所谓的浅拷贝。

var obj1 = { a: 10, b: 20, c: 30 }; 
var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c };
obj2.b = 100;
console.log(obj1); // { a: 10, b: 20, c: 30 }  这里b 沒被改到
console.log(obj2); // { a: 10, b: 100, c: 30 }

上面的代码修改拷贝的对象并不会影响原来的对象,这就是属于深拷贝的类型。
关于浅拷贝:浅拷贝有很多种方式,但是最常用的一种就是“=”赋值类型,如下

var obj1 = {'age':30}
var obj2 = obj1

1、数组的拷贝

(注意下边这几种数组拷贝其实是数组的浅拷贝,但是我们可以把他当做数组的深拷贝来用,但事实是浅拷贝)

方法1:循环遍历
var arr1 = [1,2,3]
var arr2 = []
for(var i=0;i<arr1.length;i++){
  arr2[i] = arr1[i]
}
arr2[1]=100
console.log(arr1 );//[1,2,3]
console.log(arr2 );//[1,100,3]
方法2:concat方法,该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
var arr1 = [1,2,3]
var arr2 = [].concat(arr1)
arr2[1]=100
console.log(arr1 );//[1,2,3]
console.log(arr2 );//[1,100,3]
方法3:es6扩展运算符
var arr1 = [1,2,3]
var arr2 = [...arr1]
arr2[1]=100
console.log(arr1);//[1,2,3]
console.log(arr2);//[1,100,3]

到这里或许你已经发现问题了,我们给的例子中的数组都是一维数组,如果换成二维数组,上边的方法还能用吗?答案是否定的,换成了多维数组后上边的方法已经不能适用。

2、对象的拷贝

对象的扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。

let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }

DeepCopy: 深拷贝

深拷贝的实现一般是递归属性遍历

一般来说,在JavaScript中考虑复合类型的深层复制的时候,往往就是指对于Date、Object与Array这三个复合类型的处理。我们能想到的最常用的方法就是先创建一个空的新对象,然后递归遍历旧对象,直到发现基础类型的子节点才赋予到新对象对应的位置。不过这种方法会存在一个问题,就是JavaScript中存在着神奇的原型机制,并且这个原型会在遍历的时候出现,然后原型不应该被赋予给新对象。那么在遍历的过程中,我们应该考虑使用hasOenProperty方法来过滤掉那些继承自原型链上的属性:

function deepClone(obj) {
    var copy;
    if (null == obj || "object" != typeof obj) return obj;
    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }
    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = deepClone(obj[i]);
        }
        return copy;
    }
    // Handle Object
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = deepClone(obj[attr]);
        }
        return copy;
    }
    throw new Error("Unable to copy obj! Its type isn't supported.");
}

我们来验证一下,如下代码

let arr = [1,[2,4],3]
let a = deepClone(arr)//这里deepClone函数是上边写的那个深度复制函数
a[0]=100

console.log(arr)  
console.log(a)

结果如下图


0.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容