Javascript中的深拷贝和浅拷贝

文章目录

  1. JavaScript中的变量类型
  2. 深拷贝和浅拷贝的理解
  3. 深拷贝和浅拷贝的实现方式
  4. 为什么需要深拷贝和浅拷贝

JavaScript中的变量类型

(1)、基本类型

  JavaScript中的基本类型有五种: null、undefined、boolean、string、number。 变量是按值存放的,存放在栈中的简单数据段,可以直接访问。

(2)、引用类型

  引用类型包括对象和数组,其存储在堆当中,而变量是指针,指向堆。 当我们访问的时候,实际上是访问指针,然后指针去寻找对象或数组。

深拷贝与浅拷贝的理解

(1)、深拷贝

  先新建一个空对象,内存中新开辟一块地址,把被复制对象的所有可枚举的(注意可枚举的对象)属性方法一一复制过来,注意要用递归来复制子对象里面的所有属性和方法,直到子子.....属性为基本数据类型。关键点:开辟新内存、递归复制。 

  另外一种定义:深拷贝指的是对象属性所引用的对象全部进行新建对象复制,以保证深复制的对象的引用图不包含任何原有对象或对象图上的任何对象,隔离出两个完全不同的对象图。

(2)、浅拷贝

  一个对象复制另外一个对象,如果不是深拷贝,就是浅拷贝。 简单地说,浅拷贝就是将一个对象的内存地址的“”编号“”复制给另一个对象。即在真正访问的时候还是会访问到被复制对象。 或者只是深拷贝了第一层的引用类型,而没有拷贝更深层次的应用类型,而是利用复制地址的方式,这也是浅拷贝。

深拷贝和浅拷贝的实现方式

浅拷贝

浅拷贝1

        var obj1 = {
            name: ‘wayne‘
        }
        var obj2 = obj1
        obj2.name = ‘hedy‘
        console.log(obj1.name) // ‘hedy‘

  这里首先创建了一个 obj1 对象,然后将obj复制给了 obj2, 但是这里仅仅是指针的复制,所以在修改 obj2.name 的时候,实际上是修改的同一个堆中的对象,既浅拷贝。

浅拷贝2

       var obj = {
            a: 1,
            b: {
                d: {
                    e: ‘test‘
                }
            },
            c: [1, 2, 3]
        }

        function shallowClone1(copyObj) {
            var newObj = {};
            for (var prop in copyObj) {
                newObj[prop] = copyObj[prop];
            }
            return newObj;
        }

        var newObj = shallowClone1(obj); 

        console.log(newObj.b.d === obj.b.d); // true

  即通过for in的形式将对象进行复制,这里可以看到复制只是对于指针的复制,得到的新的对象还是指向同一个堆中的对象,所以是浅复制。

浅拷贝3

Object.assign()

        var obj1 = {
            name: ‘wayne‘,
            age: 22,
            other: {
                hobby: ‘table‘,
                school: ‘xjtu‘
            }
        }
        var obj2 = Object.assign({}, obj1);
        obj2.name = ‘hedy‘
        console.log(obj1.name) // wayne

        obj2.other.hobby = ‘sing‘
        console.log(obj1.other.hobby) // sing

只从表面上来看,似乎Object.assign()的目标对象是{},是一个新的对象(开辟了一块新的内存空间),是深拷贝。

当我们修改obj2.name的时候,obj1.name没有改变,但是当我们修改 obj2.other.hobby 的时候,obj1.other.hobby 同样也发生了变化。 

即Object.assign()也是浅拷贝,或者说只是深拷贝了第一层,这样我们认为它还是浅拷贝。 

浅拷贝4

concat

        var a = [2, [3,5,7], {name: ‘wayne‘}];
        var b = a.concat(4)
        a[0] = 3;
        console.log(b[0]) // 2 看起来像深复制
        a[1][0] = 666;
        console.log(b[1][0]) // 666 浅复制
        a[2].name = ‘hedy‘
        console.log(b[2].name) // hedy 浅复制

可以看到通过concat返回的新数组,只有改变其中一个的布尔值、字符串、数值,另一个不会改变,但是改变其中的对象、数组时,可以发现,另一个也在同时改变,即还是引用原来的堆中的内容。

slice

        var a = [2, [3,5,7], {name: ‘wayne‘}];
        var b = a.slice(0)
        a[0] = 3;
        console.log(b[0]) // 2 看起来像深复制
        a[1][0] = 666;
        console.log(b[1][0]) // 666 浅复制
        a[2].name = ‘hedy‘
        console.log(b[2].name) // hedy 浅复制

这段代码仅仅是将上一段中的concat修改为了slice,发现结果也是一样的,即slice方法得到的也是浅复制。

深拷贝

深拷贝1

JSON.stringify() 和 JSON.parse()

        var obj1 = {
            name: ‘wayne‘,
            age: 22,
            other: {
                hobby: ‘table‘,
                school: ‘xjtu‘
            }
        }
        var obj2 = JSON.parse(JSON.stringify(obj1));
        obj2.name = ‘hedy‘
        console.log(obj1.name) // wayne

        obj2.other.hobby = ‘sing‘
        console.log(obj1.other.hobby) // table

可以看出通过JSON.stringify先将对象转化为字符换,然后再通过JSON.parse()转化为对象,这个对象就是完全在开辟的新的内存空间中的对象 。

深拷贝2

jquery $.clone(true) / $.extend(true)

        var x = {
            a: 1,
            b: { f: { g: 1 } },
            c: [ 1, 2, 3 ]
        };

        var y = $.extend({}, x),          //浅复制
            z = $.extend(true, {}, x);    //深复制

        console.log(y.b.f === x.b.f )    // true
        console.log(z.b.f === x.b.f)     // false

可以看到通过 $.extend() 传入第一个参数 true, 就可以进行深复制了。

推荐文章:https://www.zhihu.com/question/23031215

       http://blog.csdn.net/waiterwaiter/article/details/50267787

时间: 2024-10-27 08:44:34

Javascript中的深拷贝和浅拷贝的相关文章

深入剖析javaScript中的深拷贝和浅拷贝

在面试时经常会碰到面试官问:什么是深拷贝和浅拷贝,请举例说明?如何区分深拷贝与浅拷贝,简单来说,假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,如果B没变,那就是深拷贝:我们先看两个简单的案例: //案例1(深拷贝) var a1 = 1, a2= a1; console.log(a1) //1 console.log(a2) //1 a2 = 2; //修改 a2 console.log(a1) //1 console.log(a2) //2 //案例2(浅拷

Java中的深拷贝和浅拷贝 原型模式

1: Java中浅拷贝和深拷贝的定义:      浅拷贝:就是指两个对象共同拥有同一个值,一个对象改变了该值,也会影响到另一个对象.      深拷贝:就是两个对象的值相等,但是互相独立. (深拷贝才是真正的拷贝,浅拷贝只是将引用指向了同一份对象) 2:Java中几种常见的拷贝操作: (1)"="操作:也就是赋值操作: (2)拷贝构造函数:拷贝构造函数就是构造函数的参数的类型是该构造函数所在的类,即参数就是该类的一个对象. <span style="font-size:

浅谈Java中的深拷贝和浅拷贝

浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: [java] view plaincopyprint? int apples = 5; int pears = apples; int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float

**Python中的深拷贝和浅拷贝详解

Python中的深拷贝和浅拷贝详解 这篇文章主要介绍了Python中的深拷贝和浅拷贝详解,本文讲解了变量-对象-引用.可变对象-不可变对象.拷贝等内容. 要说清楚Python中的深浅拷贝,需要搞清楚下面一系列概念: 变量-引用-对象(可变对象,不可变对象)-切片-拷贝(浅拷贝,深拷贝) [变量-对象-引用] 在Python中一切都是对象,比如说:3, 3.14, 'Hello', [1,2,3,4],{'a':1}...... 甚至连type其本身都是对象,type对象 Python中变量与C/

python中的深拷贝和浅拷贝

1.深拷贝VS浅拷贝 python中的深拷贝和浅拷贝和java里面的概念是一样的, 所谓浅拷贝就是对引用的拷贝 (里面的数据不拷贝出来,其中的数据与原对象里面数据用的是相同的地址空间) 所谓深拷贝就是对对象的资源的拷贝 (里面的数据拷贝出来.深拷贝有自己的存储空间,有自己定义的数据,跟原对象一点关系也没有) 2.对赋值的认识: 赋值:将一个对象的地址赋值给一个变量,让变量指向该地址( 旧瓶装旧酒 ) 修改不可变对象(str.tuple)需要开辟新的空间 修改可变对象(list等)不需要开辟新的空

Javascript学习之深拷贝和浅拷贝详解

在JavaScript 中,存在着这样的两种拷贝方式.分别是:深拷贝和浅拷贝,这两种拷贝在实际中非常的常见,如果读者是一个阅读源码的爱好者,相信多多少少对深拷贝和浅拷贝有所了解.本文和大家分享的就是深拷贝和浅拷贝相关内容,一起来看看吧,希望对大家 学习javascript有所帮助. 一.浅拷贝 浅拷贝在现实中最常见的表现在赋值上面,例如 <!DOCTYPE html> <html lang="en"> <head> <meta charset=

Objective-C中的深拷贝和浅拷贝

在Objective-C中对象之间的拷贝分为浅拷贝和深拷贝.说白了,对非容器类的浅拷贝就是拷贝对象的地址,对象里面存的内容仍然是一份,没有新的内存被分配.对非容器类的深拷贝就是重写分配一块内存,然后把另一个对象的内容原封不动的给我拿过来.对容器类的深拷贝是对容器中的每个元素都进行拷贝,容器类的浅拷贝是对容器里的内容不进行拷贝,两个容器的地址是不同的,但容器里的所装的东西是一样的,在一个容器中修改值,则另一个浅拷贝的容器中的值也会变化.所以对非容器类看对象是否为深拷贝还是浅拷贝就得看对象的内存地址

C++中的深拷贝和浅拷贝 QT中的深拷贝,浅拷贝和隐式共享

下面是C++中定义的深,浅拷贝 当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用.也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用.以下情况都会调用拷贝构造函数: (1)一个对象以值传递的方式传入函数体 (2)一个对象以值传递的方式从函数返回 (3)一个对象需要通过另外一个对象进行初始化. 如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝.位拷贝又称浅拷贝,后面将进行说

iOS中的 深拷贝和浅拷贝

#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { // 一: copy 与 retain 的区别 // 谁才有引用计数的概念: // 1. 堆区空间才有引用计数概念. // 2. 堆区的对象才会有引用计数. //%ld: - 1 %lu:18446744073709551615 //retain:始终是浅拷贝.引用计数每次加一. //返回对象是否可变与被复制的对象保持一致. //copy:对于