避免变异JavaScript数组
下面是我的代码避免变异JavaScript数组,javascript,arrays,typescript,Javascript,Arrays,Typescript,下面是我的代码 let traces = { ref: null, min: null, max: null, avg: null }; let learning = { "Application": "b3", "t": [ { "d": 2, "BinaryType": "Current" }, { "d": 3, "BinaryTy
let traces = { ref: null, min: null, max: null, avg: null };
let learning = {
"Application": "b3",
"t": [
{
"d": 2,
"BinaryType": "Current"
},
{
"d": 3,
"BinaryType": "Max"
},
{
"d": 4,
"BinaryType": "Avg"
},
{
"d": 5,
"BinaryType": "Min"
}
]
};
let traceArr = Object.assign([],learning.t);
traceArr.forEach(trace => {
if (trace.BinaryType == 'Current') {
traces.ref = Object.assign({}, learning);
traces.ref.t = [];
traces.ref.t.push(trace);
traces.ref.t[0].BinaryType = 'Refeyrence';
}
if (trace.BinaryType == 'Min') {
traces.min = Object.assign({}, learning);
traces.min.t = [];
traces.min.t.push(trace);
}
if (trace.BinaryType == 'Max') {
traces.max = Object.assign({}, learning);
traces.max.t = []
traces.max.t.push(trace);
}
if (trace.BinaryType == 'Avg') {
traces.avg = Object.assign({}, learning);
traces.avg.t = [];
traces.avg.t.push(trace);
}
});
console.log("Output",traces);
console.log("Traces- Should be non mutated",traceArr);
console.log("Original",learning.t)
我假设当我修改数组的内容时,原始(学习)对象的内容不会受到影响
两个问题:
- 我假设traces.ref.t=[];应更改新创建对象中的引用。不是吗
- console.log(“Original”,learning.t)输出如下: 表示内容已更改(textrefeerence,该内容已更改 在数组迭代期间修改)。为什么会这样?还有什么 我应该做些什么来避免它 “原件” [ { d:2, BinaryType:“引用范围” }, { d:3, 二进制类型:“Max” }, { d:4, 二进制类型:“平均值” }, { d:5, 二进制类型:“Min” } ]
- 我认为Object.assign()不会进行深度复制。我很确定它正在创建一个新数组,其元素指向原始数组。进行深度复制的最简单方法是将其转换为json并返回
let traceArr = JSON.parse(JSON.stringify(learning.t));
最大的缺点是,如果你复制的任何东西都有循环引用,那么它就不起作用
编辑:
为了说明发生了什么,学习对象从
let learning = {
"Application": "b3",
"t": [Object1, Object2, ...]
}
然后这种情况发生了
let traceArr = Object.assign([], learning.t);
它创建一个新数组并将learning.t的内容复制到其中。此时,Tracearl看起来像
traceArr = [Object1, Object2, ...]
然后,它循环遍历Tracearl中的项目,这些项目与learning.t中的相同对象,只是从不同的数组中指向
if (trace.BinaryType == 'Current') {
// At this point, trace === Object1
// Shallow copy of learning
traces.ref = Object.assign({}, learning);
// traces.ref = { "Application": "b3", "t": [Object1, Object2, ...] }
// Create a new array for traces.ref.t
traces.ref.t = [];
// traces.ref = { "Application": "b3", "t": [] }
// Adds Object1 (same object from learning.t) to the new array
traces.ref.t.push(trace);
// traces.ref = { "Application": "b3", "t": [Object1] }
// Modify Object1
traces.ref.t[0].BinaryType = 'Refeyrence';
}
如果不希望traces.ret.t的元素指向与learning.t相同的对象,则需要创建新对象,即需要推送trace的副本而不是trace。或者,正如我所建议的,让Tracear成为learning.t的深度副本,这样所有的对象都是新的,没有任何东西是共享的。看起来你有两个问题,但都是关于一个共享对象的变异 我假设traces.ref.t=[];应更改新创建对象中的引用。不是吗 执行
[]
将创建一个新的数组实例,但跟踪。ref
仍在一开始就使用共享跟踪
对象。您可能希望创建跟踪
对象的副本。因为它没有任何嵌套值,所以在您的情况下,使用扩展语法是实现这一点的简单方法:
const newTrace={…traces}
console.log(“Original”,learning.t)输出如下图所示,表明内容已更改(在数组迭代期间修改的文本引用)。为什么会这样?我应该做些什么来避免它呢
这是因为跟踪
对象被推入数组,然后被修改。您还可以通过使用对象排列创建浅复制来解决此问题:
newTrace.ref.t.push({…trace});
仅通过这些更改,原始代码可能如下所示:
let traces={ref:null,min:null,max:null,avg:null};
让学习={
应用程序:“b3”,
t:[
{
d:2,
二进制类型:“当前”
},
{
d:3,
二进制类型:“Max”
},
{
d:4,
二进制类型:“平均值”
},
{
d:5,
二进制类型:“Min”
}
]
};
让tracerr=Object.assign([],learning.t);
traceArr.forEach(trace=>{
如果(trace.BinaryType==“当前”){
const newTrace={…traces};
newTrace.ref=Object.assign({},learning);
newTrace.ref.t=[];
newTrace.ref.t.push({…trace});
newTrace.ref.t[0].BinaryType=“Refeyrence”;
}
如果(trace.BinaryType==“Min”){
const newTrace={…traces};
newTrace.min=Object.assign({},学习);
newTrace.min.t=[];
newTrace.min.t.push({…trace});
}
如果(trace.BinaryType==“Max”){
const newTrace={…traces};
newTrace.max=Object.assign({},学习);
newTrace.max.t=[];
newTrace.max.t.push({…trace});
}
如果(trace.BinaryType==“Avg”){
const newTrace={…traces};
newTrace.avg=Object.assign({},学习);
newTrace.avg.t=[];
newTrace.avg.t.push({…trace});
}
});
日志(“输出”,跟踪);
log(“痕迹-应该是非变异的”,traceArr);
console.log(“原件”,learning.t);
。它包含一些类型错误,但这是避免突变的最小更改数。为什么我不能初始化空数组?这对我来说是最简单的选择,然后向其中添加元素?你可以这样做,但它会向元素添加引用,而不会复制。因为数组有对象,所以需要对对象进行深度复制。如果数组是基本的,比如字符串或整数,那么浅层拷贝就足够了。我更新了我的答案,希望能更好地说明发生了什么以及为什么需要进行学习的深层拷贝。t array.const newTrace={…traces}不会有帮助。我需要traces.min.t=[]语句来帮助我停止引用旧对象,并建议traces.min.t开始引用这个新数组。否则,如何更改javascript中的引用?记住我有一个traces.min=Object.assign({},learning);在我更改引用之前。所以我正在处理一个全新的对象(浅拷贝),我不清楚想要的结果是什么。您能提供您希望在问题中打印您的最后3个控制台日志吗?您还可以执行
traces.ref={…learning,t:[]}
。目前,您正在执行Object.assign({},学习)
但是这是一个浅拷贝(与{…learning}
相同),所以t
仍然是相同的数组实例,但是执行{…learning,t:[]}
将创建一个新的空数组实例