JavaScript:深拷贝通告JSON
JavaScript: Deep Copy Circular JSON
简介:
我正在尝试编写一个深度复制方法,但需要跟踪我访问过的节点,这样我就可以 link 到之前的 visitedNode
而不是永远深度复制直到堆栈溢出。
尝试次数:
var visitedNodes = {};
var obj = {}; obj.a = obj; // circular; can't use JSON.stringify)
var obj2 = {};
visitedNodes[obj] = "should need key obj (not obj2) to access this string";
console.log(visitedNodes[obj2]); // logs the string unfortunately
我没有存储内存位置的独特方法——它自己存储在 [object Object]
并且我不能使用 JSON.stringify 因为它是一个循环结构
我尝试使用 var visitedNodes = new Map();
但仍然没有骰子
我目前的方法是利用Array.prototype.indexOf
函数,但我不知道它是否也适用于循环结构,因为我这里也出现堆栈溢出!!!
this.clone = function (item, visitedNodes) {
visitedNodes = visitedNodes || [];
if (typeof item === "object" && !Array.isArray(item)) {
if (visitedNodes.indexOf(item) === -1) {
var cloneObject = {};
visitedNodes.push(cloneObject);
for (var i in item) {
if (item.hasOwnProperty(i)) {
cloneObject[i] = this.clone(item[i], visitedNodes);
}
}
return cloneObject;
} else {
return visitedNodes[visitedNodes.indexOf(item)];
}
}
else if (typeof item === "object" && Array.isArray(item)) {
if (visitedNodes.indexOf(item) === -1) {
var cloneArray = [];
visitedNodes.push(cloneArray);
for (var j = 0; j < item.length; j++) {
cloneArray.push(this.clone(item[j], visitedNodes));
}
return cloneArray;
} else {
return visitedNodes[visitedNodes.indexOf(item)];
}
}
return item; // not object, not array, therefore primitive
};
问题:
任何人有任何关于获得唯一内存地址的想法,以便我可以确定我之前是否访问过该对象的引用?我相信我可以基于 Object.keys()
和 Object.prototype.constructor
构造一个唯一的散列,但这看起来很荒谬,如果构造函数相同并且子键与父键相同,则会给出误报
在 visitedNodes 中保存原始引用,并创建另一个数组来保存具有相同索引的克隆对象,以便在引用时使用。
function deepClone(obj) {
var visitedNodes = [];
var clonedCopy = [];
function clone(item) {
if (typeof item === "object" && !Array.isArray(item)) {
if (visitedNodes.indexOf(item) === -1) {
visitedNodes.push(item);
var cloneObject = {};
clonedCopy.push(cloneObject);
for (var i in item) {
if (item.hasOwnProperty(i)) {
cloneObject[i] = clone(item[i]);
}
}
return cloneObject;
} else {
return clonedCopy[visitedNodes.indexOf(item)];
}
}
else if (typeof item === "object" && Array.isArray(item)) {
if (visitedNodes.indexOf(item) === -1) {
var cloneArray = [];
visitedNodes.push(item);
clonedCopy.push(cloneArray);
for (var j = 0; j < item.length; j++) {
cloneArray.push(clone(item[j]));
}
return cloneArray;
} else {
return clonedCopy[visitedNodes.indexOf(item)];
}
}
return item; // not object, not array, therefore primitive
}
return clone(obj);
}
var obj = {b: 'hello'};
obj.a = { c: obj };
var dolly = deepClone(obj);
obj.d = 'hello2';
console.log(obj);
console.log(dolly);
Fetz 的答案中的代码运行良好但在 Date 对象上中断。这是一个补丁版本:
const visitedNodes = [];
const clonedCopy = [];
function clone(item) {
if (typeof item === 'object') {
if (item instanceof Date) { // Date
if (visitedNodes.indexOf(item) === -1) {
visitedNodes.push(item);
var cloneObject = new Date(item);
clonedCopy.push(cloneObject);
return cloneObject;
}
return clonedCopy[visitedNodes.indexOf(item)];
} else if (XMLDocument && item instanceof XMLDocument) { // XML Document
if (visitedNodes.indexOf(item) === -1) {
visitedNodes.push(item);
const cloneObject = item.implementation.createDocument(item.documentElement.namespaceURI, null, null);
const newNode = cloneObject.importNode(item.documentElement, true);
cloneObject.appendChild(newNode);
clonedCopy.push(cloneObject);
return cloneObject;
}
return clonedCopy[visitedNodes.indexOf(item)];
} else if (!Array.isArray(item)) { // Object
if (visitedNodes.indexOf(item) === -1) {
visitedNodes.push(item);
var cloneObject = {};
clonedCopy.push(cloneObject);
for (const i in item) {
if (item.hasOwnProperty(i)) {
cloneObject[i] = clone(item[i]);
}
}
return cloneObject;
}
return clonedCopy[visitedNodes.indexOf(item)];
} else if (Array.isArray(item)) { // Array
if (visitedNodes.indexOf(item) === -1) {
const cloneArray = [];
visitedNodes.push(item);
clonedCopy.push(cloneArray);
for (let j = 0; j < item.length; j++) {
cloneArray.push(clone(item[j]));
}
return cloneArray;
}
return clonedCopy[visitedNodes.indexOf(item)];
}
}
return item; // not date, not object, not array, therefore primitive
}
return clone(obj);
我更愿意编辑 Fetz 的答案,但编辑队列已满。
编辑 19/07/2017:添加了XML 文档克隆
简介:
我正在尝试编写一个深度复制方法,但需要跟踪我访问过的节点,这样我就可以 link 到之前的 visitedNode
而不是永远深度复制直到堆栈溢出。
尝试次数:
var visitedNodes = {};
var obj = {}; obj.a = obj; // circular; can't use JSON.stringify)
var obj2 = {};
visitedNodes[obj] = "should need key obj (not obj2) to access this string";
console.log(visitedNodes[obj2]); // logs the string unfortunately
我没有存储内存位置的独特方法——它自己存储在 [object Object]
并且我不能使用 JSON.stringify 因为它是一个循环结构
我尝试使用 var visitedNodes = new Map();
但仍然没有骰子
我目前的方法是利用Array.prototype.indexOf
函数,但我不知道它是否也适用于循环结构,因为我这里也出现堆栈溢出!!!
this.clone = function (item, visitedNodes) {
visitedNodes = visitedNodes || [];
if (typeof item === "object" && !Array.isArray(item)) {
if (visitedNodes.indexOf(item) === -1) {
var cloneObject = {};
visitedNodes.push(cloneObject);
for (var i in item) {
if (item.hasOwnProperty(i)) {
cloneObject[i] = this.clone(item[i], visitedNodes);
}
}
return cloneObject;
} else {
return visitedNodes[visitedNodes.indexOf(item)];
}
}
else if (typeof item === "object" && Array.isArray(item)) {
if (visitedNodes.indexOf(item) === -1) {
var cloneArray = [];
visitedNodes.push(cloneArray);
for (var j = 0; j < item.length; j++) {
cloneArray.push(this.clone(item[j], visitedNodes));
}
return cloneArray;
} else {
return visitedNodes[visitedNodes.indexOf(item)];
}
}
return item; // not object, not array, therefore primitive
};
问题:
任何人有任何关于获得唯一内存地址的想法,以便我可以确定我之前是否访问过该对象的引用?我相信我可以基于 Object.keys()
和 Object.prototype.constructor
构造一个唯一的散列,但这看起来很荒谬,如果构造函数相同并且子键与父键相同,则会给出误报
在 visitedNodes 中保存原始引用,并创建另一个数组来保存具有相同索引的克隆对象,以便在引用时使用。
function deepClone(obj) {
var visitedNodes = [];
var clonedCopy = [];
function clone(item) {
if (typeof item === "object" && !Array.isArray(item)) {
if (visitedNodes.indexOf(item) === -1) {
visitedNodes.push(item);
var cloneObject = {};
clonedCopy.push(cloneObject);
for (var i in item) {
if (item.hasOwnProperty(i)) {
cloneObject[i] = clone(item[i]);
}
}
return cloneObject;
} else {
return clonedCopy[visitedNodes.indexOf(item)];
}
}
else if (typeof item === "object" && Array.isArray(item)) {
if (visitedNodes.indexOf(item) === -1) {
var cloneArray = [];
visitedNodes.push(item);
clonedCopy.push(cloneArray);
for (var j = 0; j < item.length; j++) {
cloneArray.push(clone(item[j]));
}
return cloneArray;
} else {
return clonedCopy[visitedNodes.indexOf(item)];
}
}
return item; // not object, not array, therefore primitive
}
return clone(obj);
}
var obj = {b: 'hello'};
obj.a = { c: obj };
var dolly = deepClone(obj);
obj.d = 'hello2';
console.log(obj);
console.log(dolly);
Fetz 的答案中的代码运行良好但在 Date 对象上中断。这是一个补丁版本:
const visitedNodes = [];
const clonedCopy = [];
function clone(item) {
if (typeof item === 'object') {
if (item instanceof Date) { // Date
if (visitedNodes.indexOf(item) === -1) {
visitedNodes.push(item);
var cloneObject = new Date(item);
clonedCopy.push(cloneObject);
return cloneObject;
}
return clonedCopy[visitedNodes.indexOf(item)];
} else if (XMLDocument && item instanceof XMLDocument) { // XML Document
if (visitedNodes.indexOf(item) === -1) {
visitedNodes.push(item);
const cloneObject = item.implementation.createDocument(item.documentElement.namespaceURI, null, null);
const newNode = cloneObject.importNode(item.documentElement, true);
cloneObject.appendChild(newNode);
clonedCopy.push(cloneObject);
return cloneObject;
}
return clonedCopy[visitedNodes.indexOf(item)];
} else if (!Array.isArray(item)) { // Object
if (visitedNodes.indexOf(item) === -1) {
visitedNodes.push(item);
var cloneObject = {};
clonedCopy.push(cloneObject);
for (const i in item) {
if (item.hasOwnProperty(i)) {
cloneObject[i] = clone(item[i]);
}
}
return cloneObject;
}
return clonedCopy[visitedNodes.indexOf(item)];
} else if (Array.isArray(item)) { // Array
if (visitedNodes.indexOf(item) === -1) {
const cloneArray = [];
visitedNodes.push(item);
clonedCopy.push(cloneArray);
for (let j = 0; j < item.length; j++) {
cloneArray.push(clone(item[j]));
}
return cloneArray;
}
return clonedCopy[visitedNodes.indexOf(item)];
}
}
return item; // not date, not object, not array, therefore primitive
}
return clone(obj);
我更愿意编辑 Fetz 的答案,但编辑队列已满。
编辑 19/07/2017:添加了XML 文档克隆