• 【js】对象克隆


    1. 写在前面

    介绍JavaScript的对象克隆以及两种克隆模式。

    2. 对象克隆

    对象克隆是对一个对象中的属性进行复制拷贝而产生新的对象。

    3. 浅拷贝

    先定义一个浅拷贝的函数:

    // 浅拷贝函数
    function copy(origin){
    	let target = {}
    	// for..in 遍历的属性包括对象继承的属性
    	for(prop in origin){
    		// 判断属性是否为对象的自身属性
    		if(origin.hasOwnProperty(prop)){
    			target[prop] = origin[prop];
    		}
    	}
    	return target;
    }
    

    因为for..in会遍历包含对象继承的属性,所以加一个hasOwnProperty方法限制只对对象的自身属性进行拷贝。

    然后进行测试:

    // 定义一个待拷贝对象
    let CloneObj = {
    	strAttr: '普通字符串属性',
    	arrAttr: ['数组元素01', '数组元素02'],
    	objAttr: {
    		innerStr: '内置对象字符串属性'
    	}
    }
    // 通过拷贝得到新对象
    let newObj = copy(CloneObj);
    

    测试普通属性

    // 测试普通属性
    console.log('修改之前CloneObj.strAttr:' + CloneObj.strAttr);
    newObj.strAttr = '新对象的字符串属性';
    console.log('修改之后CloneObj.strAttr:' + CloneObj.strAttr);
    console.log('newObj.strAttr:'+ newObj.strAttr);
    
    
    
    //打印结果
    修改之前CloneObj.strAttr:普通字符串属性
    修改之后CloneObj.strAttr:普通字符串属性
    newObj.strAttr:新对象的字符串属性
    

    可以看出修改新对象中的普通属性的值不会影响原来对象的属性。

    如果对象没有引用属性(数组、对象等)或不会对引用属性进行修改,浅拷贝就能满足需求。

    但如果要修改引用属性,将会对原对象的引用属性进行破坏,可以看下面的测试结果便能得知。

    测试数组和对象属性

    // 测试数组属性
    console.log('修改之前CloneObj.arrAttr[0]:' + CloneObj.arrAttr[0]);
    newObj.arrAttr[0] = '新数组元素01';
    console.log('修改之后CloneObj.arrAttr[0]:' + CloneObj.arrAttr[0]);
    console.log('newObj.arrAttr[0]:'+ newObj.arrAttr[0]);
    
    // 测试对象属性
    console.log('修改之前CloneObj.objAttr.innerStr:' + CloneObj.objAttr.innerStr);
    newObj.objAttr.innerStr = '新内置对象属性';
    console.log('修改之后CloneObj.objAttr.innerStr:' + CloneObj.objAttr.innerStr);
    console.log('newObj.objAttr.innerStr:'+ newObj.objAttr.innerStr);
    
    
    
    // 打印结果
    修改之前CloneObj.arrAttr[0]:数组元素01
    修改之后CloneObj.arrAttr[0]:新数组元素01
    newObj.arrAttr[0]:新数组元素01
    
    修改之前CloneObj.objAttr.innerStr:内置对象字符串属性
    修改之后CloneObj.objAttr.innerStr:新内置对象属性
    newObj.objAttr.innerStr:新内置对象属性
    

    因为数组或对象属性直接使用=号赋值,只是赋值一个引用指向真正的数据,新对象和源对象使用的真正的数据是同一个。

    如果要对非引用属性进行拷贝,就要使用深拷贝。

    3. 深拷贝

    // 深拷贝函数
    function deepCopy(origin){	
    	let toStr = Object.prototype.toString;
    	let arrStr = '[object Array]';
    	// 判断 origin 是数组还是对象
    	let target = (toStr.call(origin)==arrStr) ? [] : {};
    	// for..in 遍历的属性包括对象继承的属性
    	for(prop in origin){
    		// 判断属性是否为对象的自身属性
    		if(origin.hasOwnProperty(prop)){
    			// 判断属性非空以及确定是否为引用属性(使用typeof可以确定数组和对象都是object)
    			if(origin[prop] !== null && typeof(origin[prop]) == 'object'){	
    				// 若是引用属性,则使用递归赋值
    				target[prop] = deepCopy(origin[prop]);
    			}else{
    				// 普通属性直接赋值( 普通属性也就是原始值类型,Boolean、Number和String等)
    				target[prop] = origin[prop];
    			}
    		}
    	}
    	return target;
    }
    

    两个注意点:

    • 拷贝属性时,要判断是引用属性还是普通属性,普通属性则直接赋值,引用属性则使用递归赋值;
    • 在递归时,需判断是数组属性进行递归赋值还是对象属性进行递归赋值。

    4. 参考链接

  • 相关阅读:
    10月9日学习日志
    10月2日学习日志
    11月3日学习日志
    10月5日学习日志
    10月6日学习日志
    10月7日学习日志
    11月4日学习日志
    AccessDatabaseEngine.exe 32位64安装失败问题
    国产各安卓系统接收消息在杀进程后
    SAP容差组
  • 原文地址:https://www.cnblogs.com/yezhechenyang/p/14415371.html
Copyright © 2020-2023  润新知