微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么将子数组/对象的属性设置为其索引最高的同级的值?

如何解决为什么将子数组/对象的属性设置为其索引最高的同级的值?

我有一个类定义的对象,其中包含另一个类定义的对象的数组。 子类定义的对象具有一个对象数组,这些对象数组来自全局对象数组。

在下面的代码片段中,我期望以下内容

  • 项目#0:计数器:1
  • 项目#0:计数器:2
  • 项目#0:计数器:3
  • 项目1:计数器:4
  • 项目1:计数器:5
  • 第1项:计数器:6
  • 第2项:计数器:7
  • 第2项:计数器:8
  • 第2项:计数器:9

但是,下面的代码片段会产生输出

  • 项目#0:计数器:7
  • 项目#0:计数器:8
  • 项目#0:计数器:9
  • 第1项:计数器:7
  • 项目1:计数器:8
  • 第1项:计数器:9
  • 第2项:计数器:7
  • 第2项:计数器:8
  • 第2项:计数器:9

以某种方式将 ItemObj.myData 的较早版本替换为较新的记录。

为什么会发生这种情况,更重要的是,如何避免这种情况并获得预期的结果?

const NUMBER_OF_ITEMS = 3;
const ARRAY_OF_OBJ = [{"id": 1,"color": "red"},{"id": 2,"color": "green"},{"id": 3,"color": "blue"}];
let GLOBAL_COUNTER = 0;

class Itemmanager{
    constructor(){
        this.Items = [];
    for(let i = 0; i < NUMBER_OF_ITEMS; i++){
      this.Items.push(new ItemObj(i));
    }
  }  
}

class ItemObj{
    constructor(identifier){
    this.id = identifier;
    this.myData = [];
    this.getValues();
  }
  
  getValues (){
    for(let i = 0; i < ARRAY_OF_OBJ.length; i++ ){
        let myObj = Object.assign(ARRAY_OF_OBJ[i]);
      GLOBAL_COUNTER++;
      myObj.counter = GLOBAL_COUNTER;
      this.myData.push(myObj);
    }
  }
}

// Instantiate and display

const IM = new Itemmanager();

for(let Item of IM.Items){
  for(let data of Item.myData){
    $("#output").append(`<li style="color: ${data.color}">Item #${Item.id}: Counter: ${data.counter} </li>`);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
<ul id="output"></ul>
</div>

解决方法

ARRAY_OF_OBJ数组中的3个对象开始,每当调用getValues时,它们都会被多次引用:

let myObj = Object.assign(ARRAY_OF_OBJ[i]);

但是您仍然只有3个对象。 myObj只是指向这三个对象之一。

将单个对象传递给Object.assign会得到相同的对象-它不会克隆它:

const obj = {};
const obj2 = Object.assign(obj);
console.log(obj === obj2);

您需要克隆从数组中检索到的对象,否则到最后内存中仍然只有3个对象:

let myObj = { ...ARRAY_OF_OBJ[i] };

const NUMBER_OF_ITEMS = 3;
const ARRAY_OF_OBJ = [{
  "id": 1,"color": "red"
},{
  "id": 2,"color": "green"
},{
  "id": 3,"color": "blue"
}];
let GLOBAL_COUNTER = 0;

class ItemManager {
  constructor() {
    this.Items = [];
    for (let i = 0; i < NUMBER_OF_ITEMS; i++) {
      this.Items.push(new ItemObj(i));
    }
  }
}

class ItemObj {
  constructor(identifier) {
    this.id = identifier;
    this.myData = [];
    this.getValues();
  }

  getValues() {
    for (let i = 0; i < ARRAY_OF_OBJ.length; i++) {
      let myObj = { ...ARRAY_OF_OBJ[i]
      };
      GLOBAL_COUNTER++;
      myObj.counter = GLOBAL_COUNTER;
      this.myData.push(myObj);
    }
  }
}

// Instantiate and display

const IM = new ItemManager();

for (let Item of IM.Items) {
  for (let data of Item.myData) {
    $("#output").append(`<li style="color: ${data.color}">Item #${Item.id}: Counter: ${data.counter} </li>`);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
  <ul id="output"></ul>
</div>

,

使用

let myObj = Object.assign({},ARRAY_OF_OBJ[i]);

代替

let myObj = Object.assign(ARRAY_OF_OBJ[i]);

除非您提供和空对象作为第一个参数,否则

as Object.assign()将引用相同的对象。提供空对象作为第一个参数会创建一个新对象,并将第二个参数给定的对象复制到该对象。

但是请记住,它仍然是一个浅表副本;嵌套对象仍将存储为引用。

<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
 <div >
    <ul id="output"></ul>
    </div>
<script>
    const NUMBER_OF_ITEMS = 3;
    const ARRAY_OF_OBJ = [{"id": 1,"color": "red"},{"id": 2,"color": "green"},{"id": 3,"color": "blue"}];
    let GLOBAL_COUNTER = 0;

    class ItemManager{
        constructor(){
            this.Items = [];
        for(let i = 0; i < NUMBER_OF_ITEMS; i++){
          this.Items.push(new ItemObj(i));
        }
      }  
    }

    class ItemObj{
        constructor(identifier){
        this.id = identifier;
        this.myData = [];
        this.getValues();
      }
      
      getValues (){
        for(let i = 0; i < ARRAY_OF_OBJ.length; i++ ){
            let myObj = Object.assign({},ARRAY_OF_OBJ[i]);
          GLOBAL_COUNTER++;
          myObj.counter = GLOBAL_COUNTER;
          this.myData.push(myObj);
        }
      }
    }

    // Instantiate and display

    const IM = new ItemManager();

    for(let Item of IM.Items){
      for(let data of Item.myData){
        $("#output").append(`<li style="color: ${data.color}">Item #${Item.id}: Counter: ${data.counter} </li>`);
      }
    }
</script>
</body>
</html>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。