什么是最有效的方式来克隆一个JavaScript对象?我已经看到obj = eval(uneval(o));被使用,但它是非标准的,仅支持Firefox.我做了事情,如obj = JSON.parse(JSON.stringify(o));但质疑效率。
当前回答
以下是 ConroyP 上面的答案的版本,即使制造商需要参数:
//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
object_create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
function deepCopy(obj) {
if(obj == null || typeof(obj) !== 'object'){
return obj;
}
//make sure the returned object has the same prototype as the original
var ret = object_create(obj.constructor.prototype);
for(var key in obj){
ret[key] = deepCopy(obj[key]);
}
return ret;
}
此功能也在我的 simpleoo 图书馆中可用。
编辑:
下面是一个更坚实的版本(感谢Justin McCandless,现在支持自行车参考):
/**
* Deep copy an object (make copies of all its object properties, sub-properties, etc.)
* An improved version of http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
* that doesn't break if the constructor has required parameters
*
* It also borrows some code from http://stackoverflow.com/a/11621004/560114
*/
function deepCopy(src, /* INTERNAL */ _visited, _copiesVisited) {
if(src === null || typeof(src) !== 'object'){
return src;
}
//Honor native/custom clone methods
if(typeof src.clone == 'function'){
return src.clone(true);
}
//Special cases:
//Date
if(src instanceof Date){
return new Date(src.getTime());
}
//RegExp
if(src instanceof RegExp){
return new RegExp(src);
}
//DOM Element
if(src.nodeType && typeof src.cloneNode == 'function'){
return src.cloneNode(true);
}
// Initialize the visited objects arrays if needed.
// This is used to detect cyclic references.
if (_visited === undefined){
_visited = [];
_copiesVisited = [];
}
// Check if this object has already been visited
var i, len = _visited.length;
for (i = 0; i < len; i++) {
// If so, get the copy we already made
if (src === _visited[i]) {
return _copiesVisited[i];
}
}
//Array
if (Object.prototype.toString.call(src) == '[object Array]') {
//[].slice() by itself would soft clone
var ret = src.slice();
//add it to the visited array
_visited.push(src);
_copiesVisited.push(ret);
var i = ret.length;
while (i--) {
ret[i] = deepCopy(ret[i], _visited, _copiesVisited);
}
return ret;
}
//If we've reached here, we have a regular object
//make sure the returned object has the same prototype as the original
var proto = (Object.getPrototypeOf ? Object.getPrototypeOf(src): src.__proto__);
if (!proto) {
proto = src.constructor.prototype; //this line would probably only be reached by very old browsers
}
var dest = object_create(proto);
//add this object to the visited array
_visited.push(src);
_copiesVisited.push(dest);
for (var key in src) {
//Note: this does NOT preserve ES5 property attributes like 'writable', 'enumerable', etc.
//For an example of how this could be modified to do so, see the singleMixin() function
dest[key] = deepCopy(src[key], _visited, _copiesVisited);
}
return dest;
}
//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
object_create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
其他回答
没有触摸原型遗产,你可以如下深孤独的物体和岩石;
函数 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?
克罗克福德建议(我更喜欢)使用此功能:
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
var newObject = object(oldObject);
它是干净的,工作如预期,你不需要图书馆。
编辑:
这是一个对 Object.create 的聚合物,所以你也可以使用它。
var newObject = Object.create(oldObject);
注意: 如果你使用其中的一些,你可能有问题与某些 iteration谁使用 hasOwnProperty. 因为,创建创造新的空的对象,继承旧的对象. 但它仍然有用和实用的克隆对象。
例如,如果 oldObject.a = 5;
newObject.a; // is 5
但:
oldObject.hasOwnProperty(a); // is true
newObject.hasOwnProperty(a); // is false
在我以前的测试中,速度是我发现的主要担忧。
JSON.parse(JSON.stringify(obj))
是最慢的方式来深化一个对象(它比 jQuery.extend 更慢,深旗定为 10-20% )。
jQuery.extend 是相当快的,当深旗被设置为虚假(shallow clone)。这是一个很好的选择,因为它包含一些额外的逻辑的类型验证,并且不复制未定义的属性,等等,但这也将放缓你下一点。
如果你知道你正在试图克隆的对象的结构,或者可以避免深深的<unk>,你可以写一个简单的为(var i in obj) loop 克隆你的对象,同时检查 hasOwnProperty 它会比 jQuery 快得多。
var clonedObject = {
knownProp: obj.knownProp,
..
}
更新 ES6
Object.assign({}, obj);
对于清晰的旧的JavaScript对象,在现代运行时间中克隆对象的一种尝试和真正的好方法是简单的:
var clone = JSON.parse(JSON.stringify(obj));
现在,对于非清晰的JavaScript对象,没有一个真正简单的答案。 事实上,它不能因为JavaScript功能的动态性质和内部对象状态。 深度克隆一个JSON结构与内部功能需要你重建这些功能和它们的内部背景。
我们写了自己的,但我见过的最佳通用方法在这里覆盖:
首頁 〉外文書 〉文學 〉文學 〉 http://davidwalsh.name/javascript-clone
这是有效的吗? Heck 是的. 因为目标是产生一个真正的深复制克隆,那么你将不得不走路的成员的来源对象图。
所以你去吧!两个方法,我认为两者都是有效的。
使用今天的JavaScript来克隆一个对象:ECMAScript 2015(以前被称为ECMAScript 6)
var original = {a: 1};
// Method 1: New object with original assigned.
var copy1 = Object.assign({}, original);
// Method 2: New object with spread operator assignment.
var copy2 = {...original};
旧浏览器可能不支持 ECMAScript 2015. 一个常见的解决方案是使用 JavaScript-to-JavaScript 编译器,如 Babel 发行您的 JavaScript 代码的 ECMAScript 5 版本。
正如 @jim-hall 指出的那样,这只是一个微小的副本. 属性属性被复制为参考:更改一个将改变另一个对象/实例的值。
推荐文章
- 如何让元素被点击(对于整个文档)?
- 我如何检查如果一个变量是JavaScript字符串?
- 如何检测如果多个键被按下一次使用JavaScript?
- 如何通过history. pushstate获得历史变化的通知?
- 使用jQuery改变输入字段的类型
- 在JavaScript中,什么相当于Java的Thread.sleep() ?
- 使用jQuery以像素为整数填充或边距值
- 检查是否选择了jQuery选项,如果没有选择默认值
- Next.js React应用中没有定义Window
- 如何重置笑话模拟函数调用计数之前,每次测试
- 如何强制一个功能React组件渲染?
- 在javascript中从平面数组构建树数组
- 将Dropzone.js与其他字段集成到现有的HTML表单中
- 如何在AngularJS中观察路由变化?
- JavaScript DOM删除元素