精华内容
下载资源
问答
  • 变对象不可变对象,值类型,引用类型,浅拷贝,深拷贝

    乍一看,好像有一些相通之处。

    1. 可变对象和不可变对象

    python中一切对象,类型也是对象
    python中不可变类型有int,sring,tuple
    可变类型有list和dict

    看下面代码:

    # 不可变对象
    >>> a = 1
    >>> id(a)
    1752564208
    >>> a = 2
    >>> id(a)
    1752564240
    
    #可变对象
    >>> la = [1,2,3]
    >>> id(la)
    2006131817800
    >>> la[0] = 5
    >>> id(la)
    2006131817800
    >>> la = [3,4,5]
    >>> id(la)
    2006131818248

    可以看到,int类型只要改变就是整个值得改变,而list类型的改变是内部元素的改变,当list整个全部改变的时候,它在内存中的地址也会发生变换,那么string呢,在C语言中string不也是一串char吗,看看

    >>> str = "hello"
    >>> id(str)
    2006131950176
    >>> str[0]
    'h'
    >>> str[0] = "w"
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'str' object does not support item assignment

    也就是是说在python中string不能像list一样理解,它是不可只改变内部元素值的,只要变就是全部变

    总结: 可变对象和不可变对象的区别在于这个对象指向的这个地址是否允许它改变,允许则可变,不允许则不可变,如果要变,就要挪地方(改变地址)

    2. 值类型和引用类型

    前面已经说了可变类型与不可变类型了,值类型和引用类型与前面的概念十分相似。
    看代码

    # 值类型
    >>> a = 1
    >>> b =a
    >>> id(a)
    1752564208
    >>> id(b)
    1752564208
    >>> b = 2
    >>> id(b)
    1752564240
    >>> id(a)
    1752564208
    
    #引用类型
    >>> la = [1,2,3]
    >>> lb = la      # lb是la的引用
    >>> id(la)
    1978265648264
    >>> id(lb)
    1978265648264
    >>> lb[0] = 5    # 改变引用对象中单个元素
    >>> lb
    [5, 2, 3]
    >>> la
    [5, 2, 3]
    >>> id(lb)
    1978265648264
    >>> id(la)
    1978265648264
    >>> lb = [2,3,4]    # 改变引用对象中所有元素的值
    >>> la
    [5, 2, 3]
    >>> lb
    [2, 3, 4]
    >>> id(la)
    1978265648264
    >>> id(lb)
    1978265648904

    想必已经很清晰了,可变对象和不可变对象,值类型和引用类型本质上是一样一样的东西,由于对象的可变与不可变才导致了对象是引用类型或者值类型
    所以,值类型有int, string ,tuple等,
    引用类型有list,dict等

    3. 浅拷贝,深拷贝

    知道了可变与不可变的intuition之后,浅拷贝和深拷贝就很简单了,区别在于,前面两种看的是他们的区别,而拷贝着重的他们的相同,看代码:

    >>> la = [1,2,[3,4,5]]
    >>> lb = la
    >>> [id(x) for x in la]
    [1752564208, 1752564240, 2065380752328]
    >>> [id(x) for x in lb]
    [1752564208, 1752564240, 2065380752328]
    >>> lc = copy.copy(la)
    >>> [id(x) for x in lc]
    [1752564208, 1752564240, 2065380752328]
    >>> ld = copy.deepcopy(la)
    >>> [id(x) for x in ld]
    [1752564208, 1752564240, 2065380752200]
    >>> id(la)
    2065380751880
    >>> id(lb)
    2065380751880
    >>> id(lc)
    2065380638792
    >>> lc[2][0] = 0
    >>> lc
    [1, 2, [0, 4, 5]]
    >>> la
    [1, 2, [0, 4, 5]]
    >>> ld[2][0] = 9
    >>> ld
    [1, 2, [9, 4, 5]]
    >>> la
    [1, 2, [0, 4, 5]]

    其中lb,lc是浅拷贝,ld是深拷贝,浅拷贝是把对象内部的对象都看成可变类型来处理,而深拷贝是把对象内部的对象是否可变都分的很清楚。
    注意: 浅拷贝时lc[2][0] = 0 虽然只是改变了第三个元素的第一个值但是不能写lc[2] = [0,4,5],因为这样写的话,解释器会认为你是全部改变了这个可变类型的值,从而重新给lc一个地址

    展开全文
  • 写前端的时候经常会遇到对象的拷贝,一般我们...总结一下常用的对象深拷贝以及数组对象的深拷贝。1. 序列化转成json字符串深拷贝,以及存在的问题; 2. Object.assign()深拷贝,以及存在的问题; 3. 循环递归深拷贝。

    写前端的时候经常会遇到对象的拷贝,一般我们会用到深拷贝,深拷贝就是完完整整的将一个对象从内存中拷贝一份出来,放到另一块新开辟的内存中去。向下面这种赋值是浅拷贝,a、b都是对同一块内存进行引用,a、b哪一个变量修改对象的属性值都会相互影响。总结一下常用的对象深拷贝以及数组对象的深拷贝。

    var a = {id:"",name:""}
    var b = a;
    
    1. 序列化转成json字符串深拷贝,以及存在的问题
    2. Object.assign()深拷贝,以及存在的问题
    3. 循环递归深拷贝

    一、序列化转成json字符串深拷贝

    例:

    let source = {"id":1};
    //序列化转成json字符串
    let jsonStr = JSON.stringify(source)
    //反序列化为对象
    let target = JSON.parse(jsonStr);
    

    存在的问题:
    此方法仅在原对象包含可序列化值类型且没有任何循环引用时才有效。不可序列化值类型的一个例子是 Date 对象 - JSON.parse 只能将其解析为字符串而无法解析回其原始的 Date 对象

    注:
    同时总结java的序列化
    序列化:就是把一个java对象转成字节流
    反序列化:就是把字节流转成java对象
    当然序列化不仅仅可以是转成字节流或者json字符串,还有很多种方式
    为什么在java对象要序列化,什么场景要序列化?
    如果没有序列化,怎么把一个在内存里面的对象保存到文件里面去,怎么把内存的对象通过网络传输到另一台计算机的内存去呢?序列化就是把内存的对象转成字节流或者json字符串等方式进行传输用的,用在一些保存对象到文件、网络传输对象等io流传输对象的场景。


    二、Object.assign()深拷贝

    Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
    基本语法:Object.assign(target, …sources)
    例:

    var source = {"id":1,name:"lin"};
    var target = Object.assign({},source);
    

    这样就可以把source对象里面的相同属性值拷贝到target对象

    存在的问题:
    如果要拷贝的对象source里面的属性不是基础类型也是对象,或者属性含有对象数组,这种方式的拷贝就不会把source对象里面的对象或者数组对象进行深拷贝
    例:

    var source = {"id":1,list:[{"name":"小明"},{"name":"小花"}]};
    var target = Object.assign({},source);
    

    这时target里面的属性list数组对象只是浅拷贝source里面的list,还是对同一块内存的引用
    也可以向下面这样优化,循环list数组里面的对象进行Object.assign拷贝,添加到一个新的数组去,然后再赋值给target.list
    例:

    let source = {"id":1,list:[{"name":"小明"},{"name":"小花"}]};
    let target = Object.assign({},source);
    //对象数组的深拷贝
    let newlist = [];
    for(let i=0;i<target.list.length;i++){
          let obj = Object.assign({}, target.list[i]);
          newlist.push(obj);
    }
    target.list = newlist;
    

    注:如果对象里面还含有对象属性,而里面的对象属性又含有对象属性,则这种方式很麻烦不合适。

    三、循环递归深拷贝

    function deepClone(obj, newObj) {
        var newObj = newObj || {};
        for (let key in obj) {
            if (typeof obj[key] == 'object') {
                let isArray = Array.isArray(obj[key]);//判断是否数组
                newObj[key] = (isArray == true ? [] : {})
                deepClone(obj[key], newObj[key]);
            } else {
                newObj[key] = obj[key]
            }
        }
        return newObj;
    }
    
    

    参考:
    网友haogemr的js 深度拷贝的几种方法

    展开全文
  • 对于iOS系统对象的复制可以参考以下规则: 可变对象的copy和mutableCopy方法都是深拷贝(区别完全深拷贝与单层深拷贝). 不可变对象的copy方法是浅...自定义对象没有什么可变不可变的概念,因此,只讨论深拷贝的情况....
    对于iOS系统对象的复制可以参考以下规则:
    1. 可变对象的copy和mutableCopy方法都是深拷贝(区别完全深拷贝与单层深拷贝).
    2. 不可变对象的copy方法是浅拷贝,mutableCopy方法是深拷贝.
    3. copy方法返回的对象都是不可变对象

    自定义对象的深拷贝

    系统对象由于有可变和不可变之分,浅拷贝和深拷贝有点复杂.自定义对象没有什么可变不可变的概念,因此,只讨论深拷贝的情况.

    自定义对象实现拷贝需要签订NSCopying或者NSMutableCopying协议,并实现copyWithZone:或者mutableCopyWithZone:.它们的实现方法类似,这里就只讲copyWithZone:

    首先,自定义类需要签订

    @interface Person : NSObject<NSCopying>
    @property (nonatomic, strong) NSString *name;//语义属性暂时用strong
    @property (nonatomic, assign) NSInteger age;
    @end

    然后实现对应的copyWithZone:方法,在实现中使用allocWithZone:方法创建一个新的对象,然后给属性赋值.属性在赋值的时候也要深拷贝一下,否则属性就是浅拷贝的,对象的深拷贝也就不完整了.完成这些后,在使用的时候就可以直接调用这个对象的copy方法了(代码如下:)

    @implementation Person
    - (id)copyWithZone:(NSZone *)zone {
        Person *p = [[Person allocWithZone:zone] init];
        //属性也要拷贝赋值
        p.name = [self.name mutableCopy];
        p.age = self.age;
        return p;
    }
    @end
    
    @implementation ViewController
    Person *p = [[Person alloc] init];
    p.name = [NSString stringWithFormat:@"%@", @"黄继业"];
    Person *copyP = [p copy];
    
    NSLog(@"p = %p, copyP = %p", p, copyP);
    NSLog(@"p.name = %p, copyP.name = %p", p.name, copyP.name);
    @end

    输出结果为:
    p = 0x60000002a080, copyP = 0x600000034020
    p.name = 0x60000002f480, copyP.name = 0x600000252f00

    如果Person对象中又有其他的自定义对象属性,那么这个对象也需要实现它的copyWithZone:方法.(代码如下:)

    @implementation Dog
    - (id)copyWithZone:(NSZone *)zone {
        Dog *d = [[[self class] allocWithZone:zone] init];
        return d;
    }
    @end
    
    @interface Person : NSObject<NSCopying>
    @property (nonatomic, strong) NSString *name;//语义属性暂时用strong
    @property (nonatomic, assign) NSInteger age;
    @property (nonatomic, strong) Dog *dog;//新增的自定义对象属性
    @end
    
    @implementation Person
    - (id)copyWithZone:(NSZone *)zone {
        Person *p = [[[self class] allocWithZone:zone] init];
        //name属性不可变的话,或者语义属性为copy的话,都可以直接赋值了
        p.name = [self.name mutableCopy];
        p.age = self.age;
        //使用自定义对象的copy方法
        p.dog = [self.dog copy];
        return p;
    }
    @end
    
    @implementation ViewController
    Person *p = [[Person alloc] init];
    p.name = [NSString stringWithFormat:@"%@", @"黄继业"];
    p.dog = [[Dog alloc] init];
    Person *copyP = [p copy];
    
    NSLog(@"p = %p, copyP = %p", p, copyP);
    NSLog(@"p.name = %p, copyP.name = %p", p.name, copyP.name);
    NSLog(@"p.dog = %p, copyP.dog = %p", p.dog, copyP.dog);
    @end

    输出结果为:
    p = 0x6000000340c0, copyP = 0x60000003e340
    p.name = 0x60000003e1e0, copyP.name = 0x600000445d30
    p.dog = 0x60000003e320, copyP.dog = 0x60000003e200

    之所以签订协议,是为了给这个类以及它的子类添加统一的copy方法.否则我们完全可以简单粗暴的自己写个方法去实现这个对象的拷贝.比如我们创建一个子类黄种人YPerson,只要重写copyWithZone:方法即可:

    @implementation YPerson
    - (id)copyWithZone:(NSZone *)zone {
        YPerson *yp = [super copyWithZone:zone];
        //给子类特有的属性赋值
        yp.address = [self.address mutableCopy];
        return yp;
    }
    @end
    
    @implementation ViewController
    YPerson *yp = [[YPerson alloc] init];
    YPerson *copyYP = [yp copy];
    NSLog(@"yp = %p, copyYP = %p", yp, copyYP);
    @end

    输出结果为:
    yp = 0x600000249e40, copyYP = 0x600000249a50

    展开全文
  • js对象深拷贝及其的几种方法

    万次阅读 2018-12-04 11:29:50
    简单来说深拷贝是拷贝储存在栈中的对象,而浅拷贝是从内存中拷贝,这就涉及到数据存放位置了,总所周知,数据大体可以分为两种数据类型,一种是基本数据类型,数据结构不是很复杂,单独可以存在内存中就可以,而另一...

    深拷贝和浅拷贝是javascript中一个比较复杂的问题,也是面试官最喜欢问的问题之一,通过这个为可以看出是否入门,深拷贝和浅拷贝也是初学者经常犯错一个点。

    简单来说深拷贝是拷贝储存在内存堆中的对象,而浅拷贝是从内存栈中拷贝,这就涉及到数据存放位置了,总所周知,数据大体可以分为两种数据类型,一种是基本数据类型,数据结构不是很复杂,单独可以存在内存中就可以,而另一种是复杂数据类型,也叫引用数据类型,例如数组和对象,是放在内存堆中存储的,而基本数据类型是放在内存中的,不涉及深拷贝和浅拷贝,也可以说基本数据类型都是深拷贝

    而引用类型数据存储比较复杂,例如var a=[1,3,4]  这句话的存储就是首先在内存栈开辟一个空间,但是内存栈当中不可以存储这种复杂数据类型,所以要把这种结构放到内存堆当中,内存堆相当于一个密码箱,而钥匙存在内存栈当中,这就构成了一个存储关系,浅拷贝var b=a简单来说就是把这份钥匙复制了一份,但内存堆当中的数据并没有复制,所以如果改变a相应b也会改变

    而深拷贝则需要在内存堆中在生成一个密码箱,生成一把新钥匙(钥匙2),这样深拷贝的两种数值不会相互影响,也可以说没有任何关系了

    方法:

    1:jq使用,$.extend({},obj)

    这两种比较基础,估计都会使用

    2:clone(obj)

    var clone = function (obj) { return JSON.parse(JSON.stringify(obj)); }

    这种方法有种缺陷,这种方法会忽略值为function以及undefied的字段,而且对date类型的支持也不太友好。 

    3:clone(obj)

    var clone = function (obj) { 
        if(obj === null) return null 
        if(typeof obj !== 'object') return obj;
        if(obj.constructor===Date) return new Date(obj); 
        var newObj = new obj.constructor ();  //保持继承链
        for (var key in obj) {
            if (obj.hasOwnProperty(key)) {   //不遍历其原型链上的属性
                var val = obj[key];
                newObj[key] = typeof val === 'object' ? arguments.callee(val) : val; // 使用arguments.callee解除与函数名的耦合
            }
        }  
        return newObj;  
    }; 

    这种方法也就使封装最好的深拷贝的方法,以下为解释:

    1、用new obj.constructor ()构造函数新建一个空的对象,而不是使用{}或者[],这样可以保持原形链的继承;
    2、用obj.hasOwnProperty(key)来判断属性是否来自原型链上,因为for..in..也会遍历其原型链上的可枚举属性。
    3、上面的函数用到递归算法,在函数有名字,而且名字以后也不会变的情况下,这样定义没有问题。但问题是这个函数的执行与函数名 factorial 紧紧耦合在了一起。为了消除这种紧密耦合的现象,需要使用 arguments.callee

    展开全文
  • 有关系统常见可变对象不可变对象的copy 和 mutableCopy网上有很多文章,一张图基本上可以说明那么本文着重要研究的是自定义对象拷贝问题,特别比如说自定义对象里面有属性可以一、对象持有另一个本类的实例对象...
  • 在python世界中可以把对象大体分成两大类:不可变对象:数字(int,float, double)、字符串、元组(tuple)、function等可变对象:字典(dict)、列表(list)、集合(set)、程序自定义的对象所谓不可变对象就是对象...
  • Js中对象深拷贝和浅拷贝

    千次阅读 2018-07-10 18:19:44
     深拷贝:拷贝对象的所有属性作为一个全新的对象。拷贝前后的对象互不影响。浅拷贝仅仅是指向被复制的内存地址,如果原地址中对象被改变了,那么深拷贝出来的对象也会相应改变。一、对象引用对象引用容易理解,直接...
  • Js复制对象/克隆对象 Js浅拷贝与深拷贝 浅拷贝和深拷贝的实现方法 前言 学习Js克隆一个对象,作为准备工作,需要理解Js中的数据类型和按值传递:Js中的数据类型和按值传递 浅拷贝最后两种方法理解的话,可以读es5...
  • Java不可变对象

    千次阅读 2017-01-12 13:45:46
    一、不可变类简介 不可变类:所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值。如JDK内部自带的很多不可变类:Interger、Long和String等。 可类:相对于不可变类,可类创建实例后可以...
  • 详解JavaScript对象深拷贝

    千次阅读 2019-04-04 13:09:25
    详解JavaScript对象深拷贝 在几乎所有编程语言中,对象都以引用形式保存给变量、复制给其他变量。JavaScript语言也是如此。因此简单的进行赋值操作进行复制仅仅是对对象数据的引用地址进行一个传递,并会将对象...
  • Object.assign() 方法用于将所有枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。 语法:Object.assign(target, …sources) target 目标对象 sources 源对象 返回值是目标对象 注意:如果...
  • es6 对象深拷贝和浅拷贝

    万次阅读 2018-10-24 09:42:21
    简介:在项目中,为了影响原有数据,在操作数据时,经常需要深拷贝一个对象,在开发过程中,实践得出。 Object.assign() 方法用于将所有枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。 ...
  • 尬谈Js对象深拷贝与浅拷贝

    千次阅读 2018-09-19 21:11:31
    浅拷贝与深拷贝都可以实现在已有对象上再生出一份的作用。但是对象的实例是存储在堆内存中然后通过一个引用值去操作对象,由此拷贝的时候就存在两种情况了:拷贝引用和拷贝实例,这也是浅拷贝和深拷贝的区别。 浅...
  • Java学习之深拷贝浅拷贝及对象拷贝的两种思路

    千次阅读 多人点赞 2017-12-18 22:22:01
    Java语言中的深拷贝、浅拷贝以及对象拷贝
  • Python对象拷贝——深拷贝与浅拷贝

    千次阅读 2016-07-17 23:00:24
    深拷贝1. 对象赋值对象的赋值实际上是对对象的引用。也就是说当把一个对象赋值给另一个对象时,只是拷贝了引用。如:>>> t1 = tuple('furzoom') >>> t2 = t1 >>> id(t1),id(t2) (139792198303936, 139792198303936)...
  • 对象的拷贝分为浅拷贝和深拷贝,浅拷贝就是只拷贝对象,但是属性拷贝,拷贝出来的对象和原来的对象共用属性,即指向同一个属性地址,深拷贝则相当于不仅拷贝了一个对象还拷贝了它的属性,即完全是两个东西,只不过...
  • js拷贝对象 浅克隆深克隆 深拷贝浅拷贝 对象简介 js程序中都是用对象结构来描述显示中一个事物,对象就是一组属性和方法的集合。 面向对象三大特点: 封装,继承,多态。 克隆对象 浅克隆是克隆 一层,深层次的对象...
  • 先说一段废话。...如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值”来传递对象。 Python通过引用计数机制实现自动垃圾回收功能,Python中的每个
  • 深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。...但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。 赋值和浅拷贝的区别 当我们把一个对象赋值...
  • 拷贝 Python 对象 浅拷贝和深拷贝

    千次阅读 2011-01-20 14:53:00
    也就是说当你创建一个 对象,然后把它赋给另一个变量的时候,Python 并没有拷贝这个对象,而是拷贝了这个对象的 引用。 比如,假设你想创建一对小夫妻的通用档案,名为 person.然后你分别为他俩拷贝一份。...
  • 对于深拷贝,浅拷贝,以及自定义的类的对象进行拷贝的总结 浅拷贝:不会产生新的对象,产生一个指针指向原来的对象的地址,也叫地址拷贝或者指针拷贝, 深拷贝:产生新的对象,有自己的内存地址,复制的是内容,对...
  • iOS 对象数组的深拷贝(NSCoding协议)

    千次阅读 2017-07-11 14:29:18
    项目过程中遇到了对象数组的使用:联系人界面——需要分区显示,如果我存放在一个数组然后每次显示都重新分组发现会有一个计算的延迟,所有我先进行分区放在了一个单例类中的字典中。当我需要用到这个联系人的界面...
  • Java深拷贝对象

    千次阅读 2012-08-09 11:14:59
    这个问题一般很多时候在面试或者实际的开发过程中都会遇到! 首先分析一下Object类提供的clone方法, ... throws CloneNotSupportedException创建并返回此对象的一个...这样做的目的是,对于任何对象 x,表达式:
  • python——深拷贝、浅拷贝

    千次阅读 2019-06-28 09:58:52
    深拷贝、浅拷贝 浅拷贝是对于一个对象的顶层...浅拷贝对不可变类型和可类型的copy不同 copy.copy对于可类型,会进行浅拷贝 copy.copy对于不可变类型,不会拷贝,仅仅是指向 #可类型 In [88]: a = [11,22,33...
  • js 赋值的两个数组、对象会相互影响,使用深拷贝方法解决
  • 随着前端技术的发展,数据驱动视图的框架设计理念越来越火,而说到数据,就不得探讨浅拷贝和深拷贝。 学习目的: 1,什么是深拷贝 2,什么是浅拷贝 3,深拷贝和浅拷贝的本质区别 4,深拷贝的方法和使用场景 ...
  • 学习Python首先我们要知道Python变量保存的是值引用 也可以说:变量是对内存及其地址的抽象 Python:一切变量都是对象 ...变量的每一次初始化,都开辟了一个新的空间,将新内容的地址赋值给...
  • 第一、复制对象的基本概念 ...NSObject自带的常用的对象有:NSNumber、NSString、NSArray、NSDictionary、NSMutableArray、NSMutableDictionay、NSMutableString,copy产生的对象不可变的,mutable

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 89,382
精华内容 35,752
关键字:

不可变对象没有深拷贝