JS 对象的深度克隆

    技术2022-08-01  70

    深度克隆和浅度克隆的最大不同之处就在于: 深度克隆出来的数据会开辟新的独立的内存空间,而浅度克隆出来的数据和原始数据共用同一个内存空间,只是多了个指向该空间的引用。

    对象浅度克隆的例子:

    可以看到简单的将obj对象赋值给obj1对象,修改其中一个对象引用指向的内存空间的数据,另一个对象引用指向的内存空间的数据也会发生改变,说明两个引用指向的是同一个数据,属于浅度克隆

    对象深度克隆例题:

    var obj = { name:'yinzhiyuan', age:12, card:['chuding','klsm'], wife:{ name:'LS', son:{ name:'xiaolei' } } } var obj1 = { }

    现在要将对象obj深度克隆给对象obj1

    注意: 变量可以存放两种类型的值: 原始值 和 引用值

    原始值代表原始数据类型的值,也叫基本数据类型,包括 Number、Stirng、Boolean、Null、Underfined。

    原始变量及他们的值储存在栈中,当把一个原始变量传递给另一个原始变量时,是把一个栈房间的东西复制到另一个栈房间,且这两个原始变量互不影响。

    引用值指的是复合数据类型的值,包括 Object(Array、null也是Object)、Function、Date、RegExp。

    引用值是把引用变量的名称储存在栈中,但是把其实际对象储存在堆中,且存在一个指针由变量名指向储存在堆中的实际对象,当把引用对象传递给另一个变量时,复制的其实是指向实际对象的指针,此时 两者指向的 是同一个数据,若通过方法改变其中一个变量的值,则访问另一个变量时,其值也会随之加以改变;但若不是通过方法 而是通过 重新赋值 此时相当于重新开了一个房间该值的原指针改变 ,则另外一个值不会随他的改变而改变。

    思路:

    遍历对象 for(var prop in obj) 1 . 判断要克隆的对象中的数据是 原始值 还是 引用值 ,原始值直接赋值(function也可直接赋值),引用值还需进行下面的判断 2 . 判断是数组还是对象(1.constructor 2.instanceof 3.toString+call(推荐)) 3 . 建立相应的数组或对象 4 . 对数组或对象中的元素回到第一步进行判断(递归)

    实现代码:

    function deepClone(origin,target){ //如果target为null 将target设为{} var target = target || {}; for(var prop in origin){//遍历对象数据 if(origin.hasOwnProperty(prop)){//(可省)判断该属性是否是对象原型链上的,是则不符合要求,不是则符合要求 if(origin[prop] !==null && typeof(origin[prop])=='object'){ //1. 不为空(typeof null 也为 object)且为引用值 if(Object.prototype.toString.call(origin[prop]) =='[object Array]' ){ //2. 3. 数组 target[prop] = []; }else{ //对象 target[prop] = {}; } //使用三目运算符代替上面的if/else target[prop] = Object.prototype.toString.call(origin[prop]) == '[object Array]'? [] : {}; //4. 递归 deepClone(origin[prop],target[prop]) }else{ //原始值和方法 target[prop] = origin[prop]; } } } // 如果target为null,需要返回新设的target对象 return target; }

    可以看到obj1对象克隆成功,且不是两个引用指向同一对象,而是两个单独的对象 当target为null时,也能输出克隆出来的对象

    Processed: 0.011, SQL: 9