6.JavaScript浅层克隆和深层克隆

JavaScript浅层克隆和深层克隆

上一篇 JavaScript原型链和继承



前言

当我们想拷贝引用值时,直接拷贝是浅层拷贝,
因为引用值拷贝的是地址,当我们想不影响原数据时,我们就要实现深层拷贝


一、浅层拷贝与深层拷贝的差别

浅克隆就是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝,如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址,所以如果其中一个对象改变了这个地址,就会影响另一个对象。

深克隆就是创建一个新的空对象,开辟一块内存,然后将原对象中的数据全部复制过去,完全切断两个对象间的联系。

区别:浅克隆和深克隆最大的区别就是对引用值的处理了,即浅克隆之后你改我也改,深克隆之后你改我不改。

二、实现深层拷贝

1.思路

首先需要一个分析环节,分析值是什么类型,是原始值就按原来的方法拷贝过来,是引
用值就分析是数组还是对象。如果是数组,就新建一个数组;如果是对象,就新建
一个对象。再一层层看,函数里面有一个递归。把所有数组,对象都遍历。
(另外还有先JSON.stringify()再JSON.parse的方法,但这个方法不能拷贝正则和函数)

2.深度克隆的步骤

1、先把所有的值都遍历一遍(看是引用值和原始值)
用 for ( var prop in obj ),对象和数组都可以使用
2、判断是原始值,还是引用值?用 typeof 判断是不是 object (数组也会被判断是object,因为JavaScript数组底层是对象构成)
1)如果是原始值就直接拷贝
2)如果是引用值,判断是数组还是对象
3、判断是数组还是对象?(方法 instanceof【看 a 的原型链上有没有 b 的原型】、
toString、constructor(看构造函数是谁),建议用 toString,另外两个有个小 bug——跨父子域不行)

  1. 如果是数组,就新建一个空数组
  2. 如果是对象,就新建一个空对象
  3. 如果是正则和Date对象就新建对象返回
  4. 如果有null,就返回null

4、建立了数组以后,挨个看数组里面是什么,都是原始值就可以直接考
过来了;或者,建立了对象以后,挨个判断对象里面的每一个值,看是原始值还是
引用值。
5、如果里面有引用值,递归

在这介绍一个运算符和一个方法:

  1. instanceof运算符用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上。存在返回true,不存在返回false。
    语法: obj instanceof Object;//true 实例obj在Object构造函数中

  2. hasOwnProperty() 方法是 Object 的原型方法(也称实例方法),它定义在 Object.prototype 对象之上,所有 Object 的实例对象都会继承 hasOwnProperty() 方法。
    语法:hasOwnProperty() 方法用来检测一个属性是否是对象的自有属性,而不是从原型链继承的。如果该属性是自有属性,那么返回 true,否则返回 false。换句话说,hasOwnProperty() 方法不会检测对象的原型链,只会检测当前对象本身,只有当前对象本身存在该属性时才返回 true。

判断要克隆的是数组还是对象我们用toString方法来:

var toStr = Object.prototype.toString, //引用,目的是简化
    arrStr = '[ Object Array ] ',//引用,目的是简化比对
    newObj= toStr.call (obj) ==arrStr ? [] : {};

我们还可以通过 instanceof运算符 来判断要克隆的是数组还是对象 ,还有用来克隆正则和时间对象的情况。
var newObj = obj instanceof Array ? [ ] : { }; 。

然后通过if (obj.hasOwnProperty(key)) 用来检测一个属性是否是对象的自有属性,而不是从原型链继承的,避免克隆不需要的属性。
最终代码:

      var obj={
            name:"dzq",
            age:21,
            date:new Date(),
            function(){},
            null:null,
            reg:new RegExp('\\w+')
        }
        function deepCopy(obj) {
        		//判断要克隆的是数组还是对象。
        	var toStr = Object.prototype.toString, //引用,目的是简化
    			arrStr = '[ Object Array ] ',//引用,目的是简化比对
    			newObj= toStr.call (obj) ==arrStr ? [] : {};
            	//用instanceof运算符就是var newObj = obj instanceof Array ? [] : {};
            	//用constructor运算符就是var newObj = new obj.constructor();
            if(obj instanceof Date) return new Date(obj);
            if(obj instanceof RegExp) return new RegExp(obj);
            	//克隆正则和Date对象的情况。
            for (var key in obj) {
            	//检测一个属性是否是对象的自有属性
                if (obj.hasOwnProperty(key)) {
                //三木运算符简化代码,判断是对象或者数组且不为空,为真则递归,不然返回值。
                    newObj[key] = typeof obj[key] === 'object' && obj[key] !== null ? deepCopy(obj[key]) : obj[key];
                }
            }
            return newObj;
        }
        var obj1 = deepCopy(obj)
        console.log(obj1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值