角/打字稿二维数组问题

时间:2019-09-24 01:24:14

标签: javascript arrays angular typescript

通过重新使用先前设置的对象(Angular / Typescript),我开始努力分配2个暗对象数组。我的结果表明,最后一个分配优先于前两个分配,我无法弄清原因。你能看看我想念的东西吗?

    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:标准名称-等级2

c:名称-项目CCC-2 //但我希望在这里:项目AAA-0

ix:1

a:标准名称-等级1

b:标准名称-等级2

c:名称-项目CCC-2 //但我希望在这里:项目BBB-1

ix:2

a:标准名称-等级1

b:标准名称-等级2

c:名称-项目CCC-2 //在此处按预期进行操作:项目CCC-2

我在做什么错了?

2 个答案:

答案 0 :(得分:1)

您正在为对象分配引用,因此criteriaArray的所有三个元素都指向criteriaLevel1criteriaLevel2相同实例


您可以选择几种方式来保持相同的模式:

Spread syntax(但请注意the compatibility matrix

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);
      }
    }
  }
}

答案 1 :(得分:0)

按值划分对象和按引用划分对象是一件棘手的事情。在第一次迭代中分配criterialLevel1时,在下一次迭代中,实际上实际上一直都在更新criteriaLeve1变量的引用。

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
    }]
  }] 
}];