我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。
如何正确克隆JavaScript对象?
我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。
如何正确克隆JavaScript对象?
当前回答
克隆对象的简单递归方法。也可以使用lodash.clone。
让克隆=(obj)=>{let obj2=Array.isArray(obj)?[] : {};for(设k为obj){obj2[k]=(obj[k]===“对象”的类型)?克隆(obj[k]):obj[k];}返回obj2;}让w={name:“Apple”,类型:[“Fuji”,“Gala”]};设x=克隆(w);w.name=“橙色”;w.types=[“Navel”];console.log(x);console.log(w);
其他回答
复制最终可能指向自身的对象的问题可以通过简单的检查来解决。每次有复制操作时,添加此复选框。它可能很慢,但应该会起作用。
我使用toType()函数显式返回对象类型。我也有自己的copyObj()函数,它在逻辑上非常相似,可以回答所有三种Object()、Array()和Date()情况。
我在NodeJS中运行它。
尚未测试。
// Returns true, if one of the parent's children is the target.
// This is useful, for avoiding copyObj() through an infinite loop!
function isChild(target, parent) {
if (toType(parent) == '[object Object]') {
for (var name in parent) {
var curProperty = parent[name];
// Direct child.
if (curProperty = target) return true;
// Check if target is a child of this property, and so on, recursively.
if (toType(curProperty) == '[object Object]' || toType(curProperty) == '[object Array]') {
if (isChild(target, curProperty)) return true;
}
}
} else if (toType(parent) == '[object Array]') {
for (var i=0; i < parent.length; i++) {
var curItem = parent[i];
// Direct child.
if (curItem = target) return true;
// Check if target is a child of this property, and so on, recursively.
if (toType(curItem) == '[object Object]' || toType(curItem) == '[object Array]') {
if (isChild(target, curItem)) return true;
}
}
}
return false; // Not the target.
}
let clone = Object.assign( Object.create( Object.getPrototypeOf(obj)), obj)
ES6解决方案,如果您想要(浅层)克隆类实例而不仅仅是属性对象。
您可以使用函数闭包来获得深度复制的所有好处,而无需深度复制。这是一个非常不同的范例,但效果很好。不要试图复制现有对象,只要在需要时使用函数实例化新对象即可。
首先,创建一个返回对象的函数
function template() {
return {
values: [1, 2, 3],
nest: {x: {a: "a", b: "b"}, y: 100}
};
}
然后创建一个简单的浅层复制函数
function copy(a, b) {
Object.keys(b).forEach(function(key) {
a[key] = b[key];
});
}
创建一个新对象,并将模板的财产复制到其中
var newObject = {};
copy(newObject, template());
但上述复制步骤不是必需的。您需要做的就是:
var newObject = template();
现在您有了一个新对象,请测试它的财产:
console.log(Object.keys(newObject));
这将显示:
["values", "nest"]
是的,这些是newObject自己的财产,而不是对另一个对象上财产的引用。让我们检查一下:
console.log(newObject.nest.x.b);
这将显示:
"b"
newObject获得了模板对象的所有财产,但没有任何依赖链。
http://jsbin.com/ISUTIpoC/1/edit?js安慰
我添加此示例是为了鼓励一些讨论,因此请添加一些评论:)
好的,这可能是浅层复制的最佳选择。If遵循了许多使用赋值的示例,但它也保留了继承和原型。它也很简单,适用于大多数类数组和对象,但有构造函数要求或只读财产的对象除外。但这意味着它对于TypedArrays、RegExp、Date、Maps、Set和Object版本的原语(Boolean、String等)失败得很惨。
function copy ( a ) { return Object.assign( new a.constructor, a ) }
其中a可以是任何Object或类构造的实例,但对于使用专门的getter和setter或具有构造函数要求的对象来说,它同样不可靠,但对于更简单的情况来说,它很难。它也能处理争论。
您也可以将其应用于原语以获得奇怪的结果,但是。。。除非它最终成为有用的黑客,谁在乎呢。
基本内置对象和数组的结果。。。
> a = { a: 'A', b: 'B', c: 'C', d: 'D' }
{ a: 'A', b: 'B', c: 'C', d: 'D' }
> b = copy( a )
{ a: 'A', b: 'B', c: 'C', d: 'D' }
> a = [1,2,3,4]
[ 1, 2, 3, 4 ]
> b = copy( a )
[ 1, 2, 3, 4 ]
由于平均get/setter、构造函数必需的参数或只读财产,以及对父亲的冒犯,因此失败。
> a = /\w+/g
/\w+/g
> b = copy( a ) // fails because source and flags are read-only
/(?:)/
> a = new Date ( '1/1/2001' )
2000-12-31T16:00:00.000Z
> b = copy( a ) // fails because Date using methods to get and set things
2017-02-04T14:44:13.990Z
> a = new Boolean( true )
[Boolean: true]
> b = copy( a ) // fails because of of sins against the father
[Boolean: false]
> a = new Number( 37 )
[Number: 37]
> b = copy( a ) // fails because of of sins against the father
[Number: 0]
> a = new String( 'four score and seven years ago our four fathers' )
[String: 'four score and seven years ago our four fathers']
> b = copy( a ) // fails because of of sins against the father
{ [String: ''] '0': 'f', '1': 'o', '2': 'u', '3': 'r', '4': ' ', '5': 's', '6': 'c', '7': 'o', '8': 'r', '9': 'e', '10': ' ', '11': 'a', '12': 'n', '13': 'd', '14': ' ', '15': 's', '16': 'e', '17': 'v', '18': 'e', '19': 'n', '20': ' ', '21': 'y', '22': 'e', '23': 'a', '24': 'r', '25': 's', '26': ' ', '27': 'a', '28': 'g', '29': 'o', '30': ' ', '31': 'o', '32': 'u', '33': 'r', '34': ' ', '35': 'f', '36': 'o', '37': 'u', '38': 'r', '39': ' ', '40': 'f', '41': 'a', '42': 't', '43': 'h', '44': 'e', '45': 'r', '46': 's' }
使用扩展语法执行对象的浅层复制。这意味着没有任何嵌套对象实例被克隆,正如您在下面的嵌套对象子实例示例中看到的那样
常量user1={name:“Alex”,地址:'公园大道15号',年龄43岁,儿童:{name:“John”}}const user2={…user1};user1.child.name='chris';console.log(用户1);console.log(用户2);
为了解决这个嵌套对象问题并执行深度复制,我们可以使用JSON.parse(JSON.stringify(someObject))
常量user1={name:“Alex”,地址:'公园大道15号',年龄43岁,儿童:{name:“John”}}const user2=JSON.parse(JSON.stringify(user1));user1.child.name='chris';console.log(用户1);console.log(用户2);