什么是最有效的方式来克隆一个JavaScript对象?我已经看到obj = eval(uneval(o));被使用,但它是非标准的,仅支持Firefox.我做了事情,如obj = JSON.parse(JSON.stringify(o));但质疑效率。
当前回答
没有触摸原型遗产,你可以如下深孤独的物体和岩石;
函数 objectClone(o){ var ot = Array.isArray(o); return o!== null && typeof o === “object”? Object.keys(o).reduce((r,k) => o[k]!== null && typeof o[k] === “object”? (r[k] = objectClone(o[k]),r) : (r[k] = o[k],r), ot?
其他回答
在 JavaScript 中,您可以写下您的 deepCopy 方法如:
function deepCopy(src) {
let target = Array.isArray(src) ? [] : {};
for (let prop in src) {
let value = src[prop];
if(value && typeof value === 'object') {
target[prop] = deepCopy(value);
} else {
target[prop] = value;
}
}
return target;
}
只有在您可以使用 ECMAScript 6 或 transpilers 时。
特性:
将不会在复制时发射输入/输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输入输
代码:
function clone(target, source){
for(let key in source){
// Use getOwnPropertyDescriptor instead of source[key] to prevent from trigering setter/getter.
let descriptor = Object.getOwnPropertyDescriptor(source, key);
if(descriptor.value instanceof String){
target[key] = new String(descriptor.value);
}
else if(descriptor.value instanceof Array){
target[key] = clone([], descriptor.value);
}
else if(descriptor.value instanceof Object){
let prototype = Reflect.getPrototypeOf(descriptor.value);
let cloneObject = clone({}, descriptor.value);
Reflect.setPrototypeOf(cloneObject, prototype);
target[key] = cloneObject;
}
else {
Object.defineProperty(target, key, descriptor);
}
}
let prototype = Reflect.getPrototypeOf(source);
Reflect.setPrototypeOf(target, prototype);
return target;
}
结构化克隆
HTML 标准包含一个内部结构化的克隆/序列化算法,可以创建对象的深度克隆,它仍然仅限于某些内置类型,但除了由 JSON 支持的少数类型之外,它还支持日期、RegExps、地图、套件、Blobs、FileLists、ImageDatas、Sparse Arrays、Typed Arrays等。
结构化Clone 全球功能由 Node 17.0 提供:
const clone = structuredClone(original);
以前版本: Node.js 的 v8 模块(如 Node 11 )直接展示了结构化序列化 API,但此功能仍然被标记为“实验性”,并在未来的版本中可更改或删除。
const v8 = require('v8');
const structuredClone = obj => {
return v8.deserialize(v8.serialize(obj));
};
直接支持浏览器:可用于Firefox 94
const clone = structuredClone(original);
class StructuredCloner {
constructor() {
this.pendingClones_ = new Map();
this.nextKey_ = 0;
const channel = new MessageChannel();
this.inPort_ = channel.port1;
this.outPort_ = channel.port2;
this.outPort_.onmessage = ({data: {key, value}}) => {
const resolve = this.pendingClones_.get(key);
resolve(value);
this.pendingClones_.delete(key);
};
this.outPort_.start();
}
cloneAsync(value) {
return new Promise(resolve => {
const key = this.nextKey_++;
this.pendingClones_.set(key, resolve);
this.inPort_.postMessage({key, value});
});
}
}
const structuredCloneAsync = window.structuredCloneAsync =
StructuredCloner.prototype.cloneAsync.bind(new StructuredCloner);
const main = async () => {
const original = { date: new Date(), number: Math.random() };
original.self = original;
const clone = await structuredCloneAsync(original);
// They're different objects:
console.assert(original !== clone);
console.assert(original.date !== clone.date);
// They're cyclical:
console.assert(original.self === original);
console.assert(clone.self === clone);
// They contain equivalent values:
console.assert(original.number === clone.number);
console.assert(Number(original.date) === Number(clone.date));
console.log("Assertions complete.");
};
main();
const structuredClone = obj => {
const oldState = history.state;
history.replaceState(obj, null);
const clonedObj = history.state;
history.replaceState(oldState, null);
return clonedObj;
};
雖然同步,但這可能非常慢。 它發生了所有與操縱瀏覽器歷史相關的頭部. 重複召喚這種方法可能會導致Chrome暫時變成無責任。
const structuredClone = obj => {
const n = new Notification('', {data: obj, silent: true});
n.onshow = n.close.bind(n);
return n.data;
};
对于想要使用 JSON.parse(JSON.stringify(obj)) 版本的人,但没有失去日期对象,您可以使用 Parse 方法的第二个论点将行转换为日期:
function clone(obj) { var regExp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/; return JSON.parse(JSON.stringify(obj), function(k, v) { if (typeof v === 'string' && regExp.test(v)) return new Date(v) return v; }) } // usage: var original = { a: [1, null, undefined, 0, {a:null}, new Date()], b: { c(){ return 0 } } } var cloned = clone(original) console.log(cloned)
有很多答案,但没有一个给了我需要的效果,我想利用jQuery的深复制的力量......但是,当它进入一个序列时,它只是复制了对序列的参考,并深复制了其中内容。
(它甚至检查 kendo.data.ObservableArray 如果你想要它! 但是, 确保你打电话 kendo.observable(newItem) 如果你想 Arrays 再次可观察。
所以,要完全复制一个现有项目,你只是这样做:
var newItem = jQuery.extend(true, {}, oldItem);
createNewArrays(newItem);
function createNewArrays(obj) {
for (var prop in obj) {
if ((kendo != null && obj[prop] instanceof kendo.data.ObservableArray) || obj[prop] instanceof Array) {
var copy = [];
$.each(obj[prop], function (i, item) {
var newChild = $.extend(true, {}, item);
createNewArrays(newChild);
copy.push(newChild);
});
obj[prop] = copy;
}
}
}