基本上,我想得到一个浅的深层副本,该副本不会使用解构来更改我的主要对象。
let a = {
name: 'lala',
testArray: [1,2,3],
object: {
name: 'object',
array: [4,5,6]
}
};
const {name, testArray, object} = a;
object.array = [...object.array, 0];
console.log(a.object.array);
let b = {
object2: {
name: 'object',
array: [4,5,6]
}
};
const object2 = {...b.object2};
object2.array = [...object2.array, 0];
console.log(b.object2.array);
我做了一个jsfiddle(为了更容易重现),提供了我编写的代码。
https://jsfiddle.net/5z71Lbja/
问题在于,当我使用第一种方法(解构)更改“子”对象时,主要对象的数组也会更改。第二种方法可以正常工作,但是我很好奇我是否可以使用解构获得相同的结果。
答案 0 :(得分:1)
不能通过解构来创建新对象,不可以。您只能选择源中存在的值,不能对其进行转换。 (您可以更改使用的变量名,但不能转换值。)我经常想要,但您不能(至少目前不是)。
您可以通过多种方式进行跳转,但实际上最简单的方法是分别制作数组的浅表副本。
一个简单的例子:
const obj = {
foo: "bar",
array: [1, 2, 3]
};
const {foo} = obj;
const array = obj.array.slice(); // or: = [...obj.array];
obj.array[0] = "one";
console.log(obj.array[0]); // "one"
console.log(array[0]); // 1
答案 1 :(得分:0)
这不可能直接实现。
let { object } = a;
object = {...object}; // Object.assign({}, object); <<
object.array = [0, ...object.array, 0];
console.log(object.array); // [0, 4, 5, 6, 0]
console.log(a.object.array); // [4, 5, 6]
答案 2 :(得分:0)
您可以通过功能或直接使用Proxy
对象来实现此目的。
Proxy
对象采用target
对象和handler
。
handler
允许您设置某些条件,例如get
和set
,这些条件可以更改将数据返回给用户的方式。我们将为此使用get
。
在下面的处理程序中,我们更改了get
功能。我们检查target[prop]
是否返回Array
或Object
。如果是这样,我们将在内存中创建一个副本,并返回该副本而不是引用。如果它不是Array
或Object
,我们只需返回原始值(字符串,数字等)
let copyHandler = {
get: function( target, prop, receiver ) {
let value = target[ prop ];
if ( Array.isArray( value ) ) return value.slice( 0 );
if ( typeof value === "object" && value.constructor.name === "Object" ) return Object.assign( {}, value );
return value;
}
}, getCopy = obj => new Proxy(obj, copyHandler);
利用getCopy
函数作为我们的破坏中间人,我们可以确保我们所有的值都返回新的引用:
const {
name,
testArray,
object
} = getCopy(a);
object.array = [...object.array, 0];
console.log(a.object.array); // [4,5,6]
console.log(object.array); // [4,5,6,0]
let copyHandler = {
get: function( target, prop, receiver ) {
let value = target[ prop ];
if ( Array.isArray( value ) ) return value.slice( 0 );
if ( typeof value === "object" && value.constructor.name === "Object" ) return Object.assign( {}, value );
return value;
}
}, getCopy = obj => new Proxy(obj, copyHandler);
let a = {
name: 'lala',
testArray: [ 1, 2, 3 ],
object: {
name: 'object',
array: [ 4, 5, 6 ]
}
};
const {
name,
testArray,
object
} = getCopy(a);
object.array = [...object.array, 0];
console.log(a.object.array); // [4,5,6]
console.log(object.array); // [4,5,6,0]
从这个意义上说,直接意味着我们可以将Object设置为仅在非结构化声明期间返回副本。
我们通过使用Proxy
和中间人函数来完成上述操作。
注意:中间人功能不是必需的,但它有助于使事情井井有条。
let destructHandler = {
get: function( target, prop, receiver ) {
if(!this.received) this.received = new Set();
let value = target[ prop ];
if(this.received.has(prop)) return value;
this.received.add(prop);
if ( Array.isArray( value ) ) return value.slice( 0 );
if ( typeof value === "object" && value.constructor.name === "Object" ) return Object.assign( {}, value );
return value;
}, destructable = obj => new Proxy(obj, destructHandler);
这里的区别在于我们的get
处理程序使用Set
来确定某个属性是否已经被抓过一次。
在首次请求引用属性(Array
或Object
)时,它将返回副本。它仍将照常返回任何原始值。
这意味着在声明/初始化/接收对象后,您可以应用destructable
代理,然后立即使用销毁从该对象中提取副本。
初始化示例代码:
let a = destructable({
name: 'lala',
testArray: [ 1, 2, 3 ],
object: {
name: 'object',
array: [ 4, 5, 6 ]
}
});
解构示例:
const {
name,
testArray,
object
} = a;
object.array = [...object.array, 0];
console.log(a.object.array); // [4,5,6]
console.log(object.array); // [4,5,6,0]
let destructHandler = {
get: function( target, prop, receiver ) {
if(!this.received) this.received = new Set();
let value = target[ prop ];
if(this.received.has(prop)) return value;
this.received.add(prop);
if ( Array.isArray( value ) ) return value.slice( 0 );
if ( typeof value === "object" && value.constructor.name === "Object" ) return Object.assign( {}, value );
return value;
}
}, destructable = obj => new Proxy(obj, destructHandler);
let a = destructable({
name: 'lala',
testArray: [ 1, 2, 3 ],
object: {
name: 'object',
array: [ 4, 5, 6 ]
}
});
const {
name,
testArray,
object
} = a;
object.array = [...object.array, 0];
console.log(object.array); // [4,5,6,0]
console.log(a.object.array); // [4,5,6]
希望这会有所帮助!祝您编码愉快!