我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。
如何正确克隆JavaScript对象?
我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。
如何正确克隆JavaScript对象?
当前回答
const objClone = { ...obj };
请注意,嵌套对象仍作为引用复制。
其他回答
根据Apple JavaScript编码指南:
// Create an inner object with a variable x whose default
// value is 3.
function innerObj()
{
this.x = 3;
}
innerObj.prototype.clone = function() {
var temp = new innerObj();
for (myvar in this) {
// this object does not contain any objects, so
// use the lightweight copy code.
temp[myvar] = this[myvar];
}
return temp;
}
// Create an outer object with a variable y whose default
// value is 77.
function outerObj()
{
// The outer object contains an inner object. Allocate it here.
this.inner = new innerObj();
this.y = 77;
}
outerObj.prototype.clone = function() {
var temp = new outerObj();
for (myvar in this) {
if (this[myvar].clone) {
// This variable contains an object with a
// clone operator. Call it to create a copy.
temp[myvar] = this[myvar].clone();
} else {
// This variable contains a scalar value,
// a string value, or an object with no
// clone function. Assign it directly.
temp[myvar] = this[myvar];
}
}
return temp;
}
// Allocate an outer object and assign non-default values to variables in
// both the outer and inner objects.
outer = new outerObj;
outer.inner.x = 4;
outer.y = 16;
// Clone the outer object (which, in turn, clones the inner object).
newouter = outer.clone();
// Verify that both values were copied.
alert('inner x is '+newouter.inner.x); // prints 4
alert('y is '+newouter.y); // prints 16
史蒂夫
正如此链接所示,使用以下代码:
let clone = Object.create(Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj));
//
// creates 'clone' method on context object
//
// var
// clon = Object.clone( anyValue );
//
!((function (propertyName, definition) {
this[propertyName] = definition();
}).call(
Object,
"clone",
function () {
function isfn(fn) {
return typeof fn === "function";
}
function isobj(o) {
return o === Object(o);
}
function isarray(o) {
return Object.prototype.toString.call(o) === "[object Array]";
}
function fnclon(fn) {
return function () {
fn.apply(this, arguments);
};
}
function owns(obj, p) {
return obj.hasOwnProperty(p);
}
function isemptyobj(obj) {
for (var p in obj) {
return false;
}
return true;
}
function isObject(o) {
return Object.prototype.toString.call(o) === "[object Object]";
}
return function (input) {
if (isfn(input)) {
return fnclon(input);
} else if (isobj(input)) {
var cloned = {};
for (var p in input) {
owns(Object.prototype, p)
|| (
isfn(input[p])
&& ( cloned[p] = function () { return input[p].apply(input, arguments); } )
|| ( cloned[p] = input[p] )
);
}
if (isarray(input)) {
cloned.length = input.length;
"concat every filter forEach indexOf join lastIndexOf map pop push reduce reduceRight reverse shift slice some sort splice toLocaleString toString unshift"
.split(" ")
.forEach(
function (methodName) {
isfn( Array.prototype[methodName] )
&& (
cloned[methodName] =
function () {
return Array.prototype[methodName].apply(cloned, arguments);
}
);
}
);
}
return isemptyobj(cloned)
? (
isObject(input)
? cloned
: input
)
: cloned;
} else {
return input;
}
};
}
));
//
好的,这可能是浅层复制的最佳选择。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' }
根据Airbnb JavaScript风格指南,有404位贡献者:
首选对象排列运算符而不是对象。指定为浅层复制物体。使用object rest操作符获取具有特定省略了财产。
// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
delete copy.a; // so does this
// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
此外,我想提醒您,尽管Airbnb几乎不建议使用对象扩散运算符方法。请记住,Microsoft Edge仍然不支持此2018功能。
ES2016+公司表>>