什么是最有效的方式来克隆一个JavaScript对象?我已经看到obj = eval(uneval(o));被使用,但它是非标准的,仅支持Firefox.我做了事情,如obj = JSON.parse(JSON.stringify(o));但质疑效率。
当前回答
通过提出新的方法 Object.fromEntries(),它支持一些浏览器的更新的版本(参考)。
const obj = { key1: {key11: “key11”, key12: “key12”, key13: {key131: 22}}, key2: {key21: “key21”, key22: “key22”}, key3: “key3”, key4: [1,2,3, {key: “value”} } const cloneObj = (obj) => { if (Object(obj)!== obj) return obj; other if (Array.isArray(obj)) return obj.map(cloneObj); return Object.fromEntries(Object.entries(obj).map(([k,v])
其他回答
结构化克隆
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;
};
因为回归只是太昂贵的JavaScript,我发现的大多数答案是使用回归,而JSON方法将错过非JSON转换部分(功能等)。所以我做了一些研究,并发现这个拖拉机技术避免它。
/*
* Trampoline to avoid recursion in JavaScript, see:
* https://www.integralist.co.uk/posts/functional-recursive-javascript-programming/
*/
function trampoline() {
var func = arguments[0];
var args = [];
for (var i = 1; i < arguments.length; i++) {
args[i - 1] = arguments[i];
}
var currentBatch = func.apply(this, args);
var nextBatch = [];
while (currentBatch && currentBatch.length > 0) {
currentBatch.forEach(function(eachFunc) {
var ret = eachFunc();
if (ret && ret.length > 0) {
nextBatch = nextBatch.concat(ret);
}
});
currentBatch = nextBatch;
nextBatch = [];
}
};
/*
* Deep clone an object using the trampoline technique.
*
* @param target {Object} Object to clone
* @return {Object} Cloned object.
*/
function clone(target) {
if (typeof target !== 'object') {
return target;
}
if (target == null || Object.keys(target).length == 0) {
return target;
}
function _clone(b, a) {
var nextBatch = [];
for (var key in b) {
if (typeof b[key] === 'object' && b[key] !== null) {
if (b[key] instanceof Array) {
a[key] = [];
}
else {
a[key] = {};
}
nextBatch.push(_clone.bind(null, b[key], a[key]));
}
else {
a[key] = b[key];
}
}
return nextBatch;
};
var ret = target instanceof Array ? [] : {};
(trampoline.bind(null, _clone))(target, ret);
return ret;
};
如果你发现自己做这种类型的事情是正常的(例如,创建 undo redo 功能 ) 它可能值得看看 Immutable.js
const map1 = Immutable.fromJS( { a: 1, b: 2, c: { d: 3 } } );
const map2 = map1.setIn( [ 'c', 'd' ], 50 );
console.log( `${ map1.getIn( [ 'c', 'd' ] ) } vs ${ map2.getIn( [ 'c', 'd' ] ) }` ); // "3 vs 50"
https://codepen.io/anon/pen/OBpqNE?编辑器=1111
对象的克隆一直是JS的担忧,但在ES6之前,我列出了在下面的JavaScript中复制对象的不同方式,想象你有下面的对象,我希望有一个深刻的副本:
var obj = {a:1, b:2, c:3, d:4};
有几种方法可以复制这个对象,而不会改变其起源:
ES5+,使用一个简单的函数来为您进行复制:函数 deepCopyObj(obj) {如果(null == obj <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk>
希望这些帮助......
深复制对象在JavaScript(我认为最好的和最简单的)
使用 JSON.parse(JSON.stringify(对象));
var obj = {
a: 1,
b: {
c: 2
}
}
var newObj = JSON.parse(JSON.stringify(obj));
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } }
二、使用创造的方法
function cloneObject(obj) {
var clone = {};
for(var i in obj) {
if(obj[i] != null && typeof(obj[i])=="object")
clone[i] = cloneObject(obj[i]);
else
clone[i] = obj[i];
}
return clone;
}
var obj = {
a: 1,
b: {
c: 2
}
}
var newObj = cloneObject(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } }
使用 Lo-Dash 的 _.cloneDeep 链接 lodash
var obj = {
a: 1,
b: {
c: 2
}
}
var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } }
使用 Object.assign() 方法
var obj = {
a: 1,
b: 2
}
var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }
但是,当
var obj = {
a: 1,
b: {
c: 2
}
}
var newObj = Object.assign({}, obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// Note: Properties on the prototype chain and non-enumerable properties cannot be copied.
使用 Underscore.js _.clone 链接 Underscore.js
var obj = {
a: 1,
b: 2
}
var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }
但是,当
var obj = {
a: 1,
b: {
c: 2
}
}
var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// (Create a shallow-copied clone of the provided plain object. Any nested objects or arrays will be copied by reference, not duplicated.)
JSBEN.CH 性能 平衡 游戏场 1~3 http://jsben.ch/KVQLd