gpt4 book ai didi

javascript - 使用扩展运算符的 ES6 对象克隆也在修改输入

转载 作者:搜寻专家 更新时间:2023-10-30 21:05:07 24 4
gpt4 key购买 nike

我有一个相当深的interface声明看起来像这样:

export interface Job {
JobId: JobId; // type JobId = string
UserId: UserId; // type UserId = string
JobName: string;
AudioFile: JobAudioFile; // this is an interface
Status: JobStatus; // this is an enum
Tracks: JobTracks[]; // 'JobTracks' is an enum
Results: JobResults; // this is an interface
Timestamps: JobTimestamps // interface
}

该接口(interface)的大部分成员本身就是接口(interface),一般架构遵循使用枚举、字符串、数组和更多接口(interface)的模式。所有代码均以 TypeScript 形式编写,转译为 JS 并以 JS 形式上传到 AWS。 (节点 8.10 在 AWS 上运行)

在代码中的某一点,我需要对 Job 进行深拷贝作为函数参数传入的实例化:

export const StartPipeline: Handler = async (
event: PipelineEvent
): Promise<PipelineEvent> => {
console.log('StartPipeline Event: %o', event);

const newBucket = await copyToJobsBucket$(event.Job);
await deleteFromOriginalBucket$(event.Job);

console.log(`Job [${event.Job.JobId}] moved to Jobs bucket: ${newBucket}`);

event.Job.AudioFile.Bucket = newBucket;
event.Job.Status = Types.JobStatus.Processing;

// update the job status

// VVV PROBLEM OCCURS HERE VVV
const msg: Types.JobUpdatedMessage = new Types.JobUpdatedMessage({ Job: Object.assign({}, event.Job) });
await Send.to$(event.Job.UserId, msg);

return { ...event };
};

JobUpdatedMessage的定义:

  export class JobUpdatedMessage extends BaseMessage {
constructor(payload: { Job: Types.Job }) {
console.log('Incoming: %o', payload);
const copy: object = { ...payload.Job };

// VVV PROBLEM ON NEXT LINE VVV
const filtered = JobUtils.FilterJobProperties(copy as Types.Job);

super(MessageTypes.JobUpdated, filtered);
}
}

问题是在调用 JobUtils.FilterJobProperties 之后, payload.Job也以一种不受欢迎和意想不到的方式发生了突变。

这是 JobUtils.FilterJobProperties 的实现:

export const FilterJobProperties = (from: Types.Job): Types.Job => {
const fieldsToRemove: string[] = [
'Transcripts.GSTT',
'Transcripts.WSTT',
'Transcripts.ASTT',
'TranscriptTracks',
'Transcripts.Stream.File',
'Transcripts.Stream.State',
'AudioFile.Bucket',
'AudioFile.S3Key',
];

let job: Types.Job = { ...from }; // LINE ONE

fieldsToRemove.forEach(field => _.unset(job, field)); // LINE TWO

return job;
};

(我在这里使用 lodash 库)

线路市场“LINE TWO”也在变异 from函数参数,即使在“LINE ONE”上我正在做我认为是 from 的深度克隆.

我知道是这种情况,因为如果我将“LINE ONE”更改为:

// super hard core deep cloning
let job: Types.Job = JSON.parse(JSON.stringify(from));

...一切都按预期进行。 from没有突变,结果 JobUpdatedMessage符合预期,StartPipelineevent参数没有从 event.Job 中删除一堆属性.

我为此苦苦挣扎了几个小时,包括重新学习我认为我知道的关于使用扩展运算符在 Es6 中克隆对象的所有知识。

为什么“LINE ONE”也会改变输入?

最佳答案

展开运算符与 Object.assign() 一样进行浅克隆

Shallow-cloning (excluding prototype) or merging of objects is now possible using a shorter syntax than Object.assign().

Spread operator

了解传播运算符和浅克隆的示例。

let obj = { 'a': { 'b' : 1 },'c': 2}

let copy = {...obj}

copy.c = 'changes only in copy' //shallow-cloned
copy.a.b = 'changed' // still reference

console.log('original\n',obj)
console.log('\ncopy',copy)

使用展开运算符对象是浅克隆所以所有第一级 属性将成为副本,而所有更深层次 属性仍将保留为引用

正如您在示例中看到的那样,c 属性不会影响原始对象,因为它是第一层深度,另一方面,b 属性更改会影响父对象属性,因为它处于深层次并且仍然是引用。

关于javascript - 使用扩展运算符的 ES6 对象克隆也在修改输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54542400/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com