Клонирование объектов ES6 с использованием оператора распространения также изменяет ввод - PullRequest
0 голосов
/ 05 февраля 2019

Я довольно глубоко объявил 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 и загружен в AWS как JS.(Узел 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 соответствует ожидаемому, а у параметра StartPipeline *1034* нет набора свойств, удаленных из event.Job.

Я боролся с часамина этом, включая повторное изучение всего, что я знал о клонировании объектов в Es6, используя оператор распространения.

Почему 'LINE ONE' также поменял вход?

1 Ответ

0 голосов
/ 05 февраля 2019

Оператор Spread выполняет поверхностное клонирование так же, как Object.assign()

Мелкое клонирование (исключая прототип) или объединение объектов теперь возможно с использованием более короткого синтаксиса, чем Object.assign ().

Оператор спреда

Пример понимания оператора спреда и мелкого клонирования.

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 изменения свойств влияют на родительские свойства, потому что он находится на глубоком уровне и все еще является ссылкой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...