代码之家  ›  专栏  ›  技术社区  ›  John Dibling

使用扩展运算符进行ES6对象克隆也在修改输入

  •  3
  • John Dibling  · 技术社区  · 6 年前

    我有相当深的感情 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
      }
    

    这个接口的大多数成员本身就是接口,通用体系结构遵循使用枚举、字符串、数组和更多接口的模式。所有代码都以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;
      };
    

    (我正在使用洛达斯图书馆)

    from 函数参数,即使在“第一行”中,我正在做我认为是 从…起

    我知道这是因为如果我将“第一行”更改为:

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

    从…起 作业更新消息 如预期的那样,以及 StartPipeline event 参数没有从中删除一组属性 event.Job

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

    为什么“第一行”也会改变输入?

    1 回复  |  直到 6 年前
        1
  •  8
  •   Code Maniac    6 年前

    Spread运算符执行的操作与 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)

    使用 spread operator shallow cloned 所以所有的 一级 更深层次 房地产仍将保持不变 references

    正如您在示例中看到的 c b 属性更改会影响父属性,因为它处于深层,并且仍然是引用。