搜集来源:(代码中的同类变量已被我修改优化为同名变量)
- 【JS】深拷贝与浅拷贝的区别,实现深拷贝的几种方法(递归一)
- js实现深拷贝(递归二、树广度一)
- JS实现深拷贝(递归一、树深度一)
- 深度优先遍历,广度优先遍历实现对象的深拷贝(树深度二、树广度二)
关于赋值、浅拷贝、深拷贝的区别
文章目录
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;
}