Угловая / машинописная двумерная задача - PullRequest
0 голосов
/ 24 сентября 2019

Я ломаю голову над выполнением присваиваний массиву 2 тусклых объектов, повторно используя ранее установленные объекты (Angular / Typescript).Мой результат показывает, что последнее назначение переопределяет два предыдущих, и я не могу понять, почему.Можете ли вы взглянуть на то, что мне не хватает?

    export interface Criteria {
        fieldValue: any;
        fieldName: string;
        childItems?: Criteria[];
    }


                        // function to build my array of objects:
    setCriteria() {
                       // parent object 1 
                       // to be reused / reassigned to array below
    const criteriaLevel1: Criteria = {
      fieldName: 'Criteria name',
      fieldValue: 'Crit-Level-1',
      childItems: []
    };
                       // parent object 2 - child of  object 1
                       // to be reused / reassigned to array below
                       // into - childItems[0]
    const criteriaLevel2: Criteria = {
      fieldName: 'Criteria name',
      fieldValue: 'Crit-Level-2',
      childItems: []
    };
                       // list of 3 different items to be assigned to array 
                       // into - childItems[0].childItems[0] of each array record.
    const itemsABC: string[] = [
      'item AAA',
      'item BBB',
      'item CCC'
    ];

    const criteriaArray = [];
    let ix = 0;

    itemsABC.forEach(item => {

      console.log('item: ' + item);

      criteriaArray[ix] = [];
      criteriaArray[ix][0] = criteriaLevel1;
      criteriaArray[ix][0].childItems[0] = criteriaLevel2;
      criteriaArray[ix][0].childItems[0].childItems[0] = {
          fieldName: 'name',
          fieldValue: item + '-' + ix
      };
      ix++;
    });

    // output test

    for (let i = 0; i < 3; i++) {
      console.log('ix: ' + i);
      for (const itemA of criteriaArray[i]) {
        console.log('a: ' + itemA.fieldName + ' - ' + itemA.fieldValue);
        for (const itemB of itemA.childItems) {
          console.log('b: ' + itemB.fieldName + ' - ' + itemB.fieldValue);
          for (const itemC of itemB.childItems) {
            console.log('c: ' + itemC.fieldName + ' - ' + itemC.fieldValue);
          }
        }
      }

    }
  }

Я получаю этот вывод:

индекс: 0 - вставка элемента: элемент AAA

Индекс: 1 - вставка элемента: элемент BBB

Индекс: 2 - вставка элемента: элемент CCC

ix: 0

a: Название критерия - Уровень критики-1

b: имя критерия - Crit-Level-2

c: имя - элемент CCC-2 // НО Я ожидаю здесь: элементAAA-0

ix: 1

a: Название критерия - Crit-Level-1

b: Название критерия - Crit-Level-2

c: name - item CCC-2 // НО Я ожидаю здесь: item BBB-1

ix: 2

a: Имя критерия - Crit-Level-1

b: Имя критерия - Crit-Level-2

c: имя - элемент CCC-2 // YES asздесь ожидается: пункт CCC-2

Что я делаю не так?

Ответы [ 2 ]

1 голос
/ 24 сентября 2019

Вы присваиваете ссылки на объекты , поэтому все три элемента criteriaArray указывают на одинаковые экземпляры criteriaLevel1 и criteriaLevel2.


У вас есть несколько вариантов для поддержки одного и того же шаблона:

Синтаксис распространения (но обратите внимание матрица совместимости )

criteriaArray[ix][0] = {...criteriaLevel1, childItems: []};
criteriaArray[ix][0].childItems[0] = {...criteriaLevel2, childItems: []};

const criteriaLevel1 = {
  fieldName: 'Criteria name',
  fieldValue: 'Crit-Level-1',
  childItems: []
};

const criteriaLevel2 = {
  fieldName: 'Criteria name',
  fieldValue: 'Crit-Level-2',
  childItems: []
};
  
const itemsABC = [
  'item AAA',
  'item BBB',
  'item CCC'
];

const criteriaArray = [];
let ix = 0;

itemsABC.forEach(item => {
  console.log('item: ' + item);

  criteriaArray[ix] = [];
  criteriaArray[ix][0] = {...criteriaLevel1, childItems: []};
  criteriaArray[ix][0].childItems[0] = {...criteriaLevel2, childItems: []};
  criteriaArray[ix][0].childItems[0].childItems[0] = {
    fieldName: 'name',
    fieldValue: item + '-' + ix
  };
    ix++;
});

for (let i = 0; i < 3; i++) {
  console.log('ix: ' + i);
  for (const itemA of criteriaArray[i]) {
    console.log('a: ' + itemA.fieldName + ' - ' + itemA.fieldValue);
    for (const itemB of itemA.childItems) {
      console.log('b: ' + itemB.fieldName + ' - ' + itemB.fieldValue);
      for (const itemC of itemB.childItems) {
        console.log('c: ' + itemC.fieldName + ' - ' + itemC.fieldValue);
      }
    }
  }
}

Object.assign()

criteriaArray[ix][0] = Object.assign({}, criteriaLevel1, {childItems: []});
criteriaArray[ix][0].childItems[0] = Object.assign({}, criteriaLevel2, {childItems: []});

const criteriaLevel1 = {
  fieldName: 'Criteria name',
  fieldValue: 'Crit-Level-1',
  childItems: []
};

const criteriaLevel2 = {
  fieldName: 'Criteria name',
  fieldValue: 'Crit-Level-2',
  childItems: []
};
  
const itemsABC = [
  'item AAA',
  'item BBB',
  'item CCC'
];

const criteriaArray = [];
let ix = 0;

itemsABC.forEach(item => {
  console.log('item: ' + item);

  criteriaArray[ix] = [];
  criteriaArray[ix][0] = Object.assign({}, criteriaLevel1, {childItems: []});
  criteriaArray[ix][0].childItems[0] = Object.assign({}, criteriaLevel2, {childItems: []});
  criteriaArray[ix][0].childItems[0].childItems[0] = {
    fieldName: 'name',
    fieldValue: item + '-' + ix
  };
    ix++;
});

for (let i = 0; i < 3; i++) {
  console.log('ix: ' + i);
  for (const itemA of criteriaArray[i]) {
    console.log('a: ' + itemA.fieldName + ' - ' + itemA.fieldValue);
    for (const itemB of itemA.childItems) {
      console.log('b: ' + itemB.fieldName + ' - ' + itemB.fieldValue);
      for (const itemC of itemB.childItems) {
        console.log('c: ' + itemC.fieldName + ' - ' + itemC.fieldValue);
      }
    }
  }
}

Обратите внимание, что оба метода выполняют поверхностное копирование, поэтому необходимо вручную учитывать ссылки на вложенные объекты.


Альтернативный подход заключается в созданиивспомогательная функция для создания нового объекта.

function generateCriteria(fieldName, fieldValue) {
  return () => ({
    fieldName: fieldName,
    fieldValue: fieldValue,
    childItems: []
  });
}

const criteriaLevel1 = generateCriteria('Criteria name', 'Crit-Level-1');
const criteriaLevel2 = generateCriteria('Criteria name', 'Crit-Level-2');

const itemsABC = [
  'item AAA',
  'item BBB',
  'item CCC'
];

const criteriaArray = [];
let ix = 0;

itemsABC.forEach(item => {
  console.log('item: ' + item);

  criteriaArray[ix] = [];
  criteriaArray[ix][0] = criteriaLevel1();
  criteriaArray[ix][0].childItems[0] = criteriaLevel2();
  criteriaArray[ix][0].childItems[0].childItems[0] = {
    fieldName: 'name',
    fieldValue: item + '-' + ix
  };
    ix++;
});

for (let i = 0; i < 3; i++) {
  console.log('ix: ' + i);
  for (const itemA of criteriaArray[i]) {
    console.log('a: ' + itemA.fieldName + ' - ' + itemA.fieldValue);
    for (const itemB of itemA.childItems) {
      console.log('b: ' + itemB.fieldName + ' - ' + itemB.fieldValue);
      for (const itemC of itemB.childItems) {
        console.log('c: ' + itemC.fieldName + ' - ' + itemC.fieldValue);
      }
    }
  }
}
0 голосов
/ 24 сентября 2019

Объект по значению и объект по ссылке - сложная вещь.Когда вы назначаете criterialLevel1 на 1-ой итерации, на следующей итерации вы фактически все время обновляете ссылку на переменную attributeLeve1.

criteriaArray[ix] = [];
criteriaArray[ix][0] = {...criteriaLevel1, childItems: []}; // creating a new object and spreading it, Note the child Items created new else as it is an array would have been passed by reference as well.
criteriaArray[ix][0].childItems[0] = {...criteriaLevel2, childItems: []};
criteriaArray[ix][0].childItems[0].childItems[0] = {
  fieldName: 'name',
  fieldValue: item + '-' + ix
};

Я бы рекомендовал вместо этого определять эти переменные, почему бы не назначить их напрямую, и вы можетесделать это в одной строке:

criteriaArray[ix] = [{
  fieldName: 'Criteria name', 
  fieldValue: 'Crit-Level-1', 
  childItems: [{
    fieldName: 'Criteria name', 
    fieldValue: 'Crit-Level-2', 
    childItems: [{
      fieldName: 'name',
      fieldValue: item + '-' + ix
    }]
  }] 
}];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...