【JavaScript 深拷贝】$.extend() 方法、自封装函数(进来拿代码套用啦!)

搜集来源:(代码中的同类变量已被我修改优化为同名变量)

  1. 【JS】深拷贝与浅拷贝的区别,实现深拷贝的几种方法(递归一)
  2. js实现深拷贝(递归二、树广度一)
  3. JS实现深拷贝(递归一、树深度一)
  4. 深度优先遍历,广度优先遍历实现对象的深拷贝(树深度二、树广度二)

关于赋值、浅拷贝、深拷贝的区别

在这里插入图片描述



JSON 对象方法

在这里插入图片描述

Object.prototype.deepClone = function() {
	return JSON.parse(JSON.stringify(this));
}

防坑注意:

在这里插入图片描述
在这里插入图片描述


【jQuery】extend()方法

  • 无论修改拷贝对象第几层嵌套层,原对象均不会被影响:
    PS:别忘了引入【jq库】在这里插入图片描述

递归函数(一)

  • 无论修改拷贝对象第几层嵌套层,原对象均不会被影响:
    【缺点】当数据的层次很深,会栈溢出,所以最好用【DFS / BFS】
    在这里插入图片描述
		// 递归封装深拷贝
		function deepClone(obj) {
			if (obj === null) {
				return null;
			} else if (typeof obj !== 'object') {
				// 不再具有下一层次
				return obj;
			} else if (obj.constructor === Date) {
				return new Date(obj);
			}

			// 保持继承链
			var objClone = new obj.constructor ();
			for (var k in obj) {

				// 不遍历其原型链上的属性
				if (obj.hasOwnProperty(k)) {

					// 判断obj子元素是否为对象,如果是,递归复制
					if (obj[k] && typeof obj[k] === 'object') {
						objClone[k] = deepClone(obj[k]);
					} else {
						objClone[k] = obj[k];
					}

					// 简写
					// objClone[k] = typeof obj[k] === 'object' ? deepClone(obj[k]) : obj[k];
				}
			}

			// 返回深度克隆后的对象
			return objClone;
		};

递归函数(二)

  • 演示图与上面一样就不发了
    【缺点】当数据的层次很深,会栈溢出,所以最好用【DFS / BFS】
		// 创建对元素进行类型判断的函数
		function getType(obj) {
			// tostring会返回对应不同的标签的构造函数
			var _toString = Object.prototype.toString;
			var map = {
				'[object Boolean]' : 'boolean',
				'[object Number]' : 'number',
				'[object String]' : 'string',
				'[object Function]' : 'function',
				'[object Array]' : 'array',
				'[object Date]' : 'date',
				'[object RegExp]' : 'regExp',
				'[object Undefined]' : 'undefined',
				'[object Null]' : 'null',
				'[object Object]' : 'object'
			};
			if (obj instanceof Element) {
				return 'element';
			}
			return map[_toString.call(obj)];
		}

		// 递归封装深拷贝
		function deepClone(obj) {
			var type = getType(obj);
			var objClone;
			if (type === 'array') {
				objClone = [];
			} else if (type === 'object') {
				objClone = {};
			} else {
				// 不再具有下一层次
				return obj;
			}

			// 类型为数组或对象时的递归复制
			if (type === 'array') {
				for (var i = 0, len = obj.length; i < len; i++) {
					objClone.push(deepClone(obj[i]));
				}
			} else if (type === 'object') {
				for (var k in obj) {
					objClone[k] = deepClone(obj[k]);
				}
			}

			// 返回深度克隆后的对象
			return objClone;
		}

【DFS】树深度优先遍历(一)

		// 深度优先深度克隆, 利用栈的方式实现
		// 防栈溢出
		function deepClone(obj) {
			var objClone = {};

			// 栈
			var loopList = [{
				parent: objClone,
				key: undefined,
				data: obj,
			}];

			while (loopList.length) {
				// 深度优先
				var node = loopList.pop();
				var parent = node.parent;
				var key = node.key;
				var data = node.data;

				// 初始化赋值目标,key为undefined则拷贝到父元素,否则拷贝到子元素
				var res = parent;
				if (typeof key !== 'undefined') {
					res = parent[key] = {};
				}
				for (var k in data) {
					if (data.hasOwnProperty(k)) {
						if (typeof data[k] === 'object') {
							// 下一次循环
							loopList.push({
								parent : res,
								key : k,
								data : data[k],
							});
						} else {
							res[k] = data[k];
						}
					}
				}
			}

			// 返回深度克隆后的对象
			return objClone;
		}

【DFS】树深度优先遍历(二)

		// 创建对元素进行类型判断的函数
		function getType(obj) {
			// tostring会返回对应不同的标签的构造函数
			var _toString = Object.prototype.toString;
			var map = {
				'[object Boolean]' : 'boolean',
				'[object Number]' : 'number',
				'[object String]' : 'string',
				'[object Function]' : 'function',
				'[object Array]' : 'array',
				'[object Date]' : 'date',
				'[object RegExp]' : 'regExp',
				'[object Undefined]' : 'undefined',
				'[object Null]' : 'null',
				'[object Object]' : 'object'
			};
			if (obj instanceof Element) {
				return 'element';
			}
			return map[_toString.call(obj)];
		}

		// 深度优先深度克隆, 利用栈的方式实现
		// 解决【递归、对象环、边界处理(比如函数,Set等)、防栈溢出】问题
		function deepClone(obj) {
			var type = getType(obj);
			var objClone = {};
			// 用于存储复制过程中访问过的对象的队列,避免对象环的问题
			var visitQueue = [];
			if (type === 'array' || type === 'object') {
				var index = visitQueue.indexOf(obj);
				if (index > -1){
					objClone = visitQueue[index]
				} else {
					visitQueue.push(obj);
					for (var key in obj) {
						objClone[key] = deepClone(obj[key], visitQueue);
					}
				}

			} else if (type === 'function') {
				// 处理函数
				objClone = eval( '(' + obj.toString() + ')');
			} else {
				// 处理原始值
				objClone = obj;
			}

			// 返回深度克隆后的对象
			return objClone;
		}

【BFS】树广度优先遍历(一)

		// 广度优先深度克隆, 利用队列的方式实现
		// 利用objClone建立一个与原对象相同的数据结构, 遇到可处理的值(比如原始值,函数,就处理后赋值到相应的节点下)
		function deepClone(obj) {
			var objClone = {};

			// 进队列
			var originQueue = [obj];

			// 同时objClone也跟着一起进队列
			var copyQueue = [objClone];

			// 以下两个队列用来保存复制过程中访问过的对象,以此来避免对象环的问题(对象的某个属性值是对象本身)
			var visitQueue = [];
			var copyVisitQueue = [];

			while (originQueue.length > 0) {
				var _obj = copyQueue.shift();
				var _data = originQueue.shift();
				copyVisitQueue.push(_obj);
				visitQueue.push(_data);
				for (var k in _data) {
					var _value = _data[k];
					if (typeof _value !== 'object') {
						_obj[k] = _value;
					} else {
						// 使用indexOf可以发现数组中是否存在相同的对象(实现indexOf的难点就在于对象比较)
						var index = visitQueue.indexOf(_value);
						if (index >= 0) {
							// 出现环的情况不需要再取出遍历
							_obj[k] = copyVisitQueue[index];
						} else {
							originQueue.push(_value);
							_obj[k] = {};
							copyQueue.push(_obj[k]);
						}
					}
				}
			}

			// 返回深度克隆后的对象
			return objClone;
		}

【BFS】树广度优先遍历(二)

		// 创建对元素进行类型判断的函数
		function getType(obj) {
			// tostring会返回对应不同的标签的构造函数
			var _toString = Object.prototype.toString;
			var map = {
				'[object Boolean]' : 'boolean',
				'[object Number]' : 'number',
				'[object String]' : 'string',
				'[object Function]' : 'function',
				'[object Array]' : 'array',
				'[object Date]' : 'date',
				'[object RegExp]' : 'regExp',
				'[object Undefined]' : 'undefined',
				'[object Null]' : 'null',
				'[object Object]' : 'object'
			};
			if (obj instanceof Element) {
				return 'element';
			}
			return map[_toString.call(obj)];
		}

		// 广度优先深度克隆, 利用队列的方式实现
		// 利用objClone建立一个与原对象相同的数据结构, 遇到可处理的值(比如原始值,函数,就处理后赋值到相应的节点下)
		function deepClone(obj) {
			var objClone = {};

			// 进队列
			var originQueue = [obj];

			// 同时objClone也跟着一起进队列
			var copyQueue = [objClone];

			// 用于存储复制过程中访问过的对象的队列,避免对象环的问题
			var visitQueue = [];
			while(originQueue.length){
				var _obj = originQueue.shift();
				var _data = copyQueue.shift();
				if (getType(_obj) === 'array' || getType(_obj) === 'object') {
					for(item in _obj){
						var val = _obj[item];
						if (getType(val) === 'object') {
							var index = visitQueue.indexOf(val);
							if (~index) {
								// 对象环
								_data[item] = visitQueue[index];
							} else {
								// 新的对象,给objClone一个对应属性的空对象
								originQueue.push(val);
								_data[item] = {};
								copyQueue.push(_data[item]);
								visitQueue.push(val);
							}
						}
						else if (getType(val) === 'array') {
							originQueue.push(val);
							_data[item] = [];
							copyQueue.push(_data[item])
						} else if (getType(val) === 'function') {
							// 处理函数
							_data[item] = eval( '(' + val.toString() + ')');
						} else {
							// 处理原始值
							_data[item] = val;
						}
					}
				} else if (getType(obj) === 'function') {
					// 处理函数
					_data = eval( '(' + _obj.toString() + ')');
				} else {
					// 处理原始值
					_data = _obj;
				}
			}
			// 返回深度克隆后的对象
			return objClone;
		}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值