【问题标题】:Scope issue - altering data in a callback is altering a higher scope范围问题 - 在回调中更改数据正在更改更高的范围
【发布时间】:2019-11-21 20:50:28
【问题描述】:

我正在构建一个小型 d&d 应用程序来练习以角度传递数据组件,但我遇到了一个奇怪的问题。

我从 API 调用中获取了一个“怪物”对象,然后将其填充到视图中一定次数。我正在尝试通过添加索引来更改其中一个值“名称” - 简单 - 获取“名称”添加和索引。我正在获取“名称”的值来更改它,然后将其推送到组件中保存的数组 - 一切正常。我认为对于循环的下一次迭代,原始值应该保持不变,但事实并非如此。我在这里的范围内不理解的东西。

尝试只发布一些代码,因为我知道问题出在哪里,而且我知道这是一个范围问题,我只是想知道为什么这是一个我不熟悉的概念。使用

export class CombatComponent implements OnInit {
  selected:number;
  monsters:any[] = []
  addedMonsters:any[] =[]

  monsterNumber:number = 0;    <----this is being passed from a form - its working

  constructor( private ms:MonsterService) { }

 <-dont want to post the entire function because this is where the issue lies ->

this.$monsterData.subscribe(data =>{
 this.currentMonster=data;

 for (let i = 0 ; i<this.monsterNumber; i++){

   let originalName = this.currentMonster.name;
   console.log(this.currentMonster.name)

   this.monsters.push(this.currentMonster)
   let newName = this.monsters[i]['name'] = this.currentMonster.name +" " + `${i+1}`
   this.monsters[i].name = newName

   console.log(this.monsters)

 }

我的问题是,在第一次迭代之后,我认为应该发生的是一个带有名称 + 索引的数组。真正发生的是第二次通过 currentMonster 的“名称”值更改为原始值 + 索引。我在这里不理解范围是什么?

【问题讨论】:

  • this.monsterNumber 始终设置为 0,您必须增加值或设置 this.monsterNumber = this.monsters.length。
  • 它实际上不是 - 它来自一个实际工作的表单。如果让我们说这个数字是 4 - 而不是 4 个项目是“项目 1”“项目 2”等 - 它的 4 个“项目 1 2 3 4”s
  • @SaurabhYadav 我也这么认为,但问题告诉 for 循环被击中,所以我认为代码被遗漏了。
  • @A1rPun,是的,循环运行良好并从页面上的表单传递

标签: javascript angular scope global


【解决方案1】:

每次迭代都将相同的怪物对象推入数组。这会导致像this.monster[1]this.monster[2] 这样的数组元素彼此持有相同的对象。因此,如果您更改monster[1],您将更改monster[2] 等等(包括currentMonster,因为它们都引用同一个对象)

我假设您实际上是在尝试基于 currentMonster 属性创建新的怪物对象并尝试为它们分配一个新名称。

//these do shallow copy of the properties
//this is regular javascript might have to make
//changes to fit typescript syntax

//using spread operator to create new object
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
let newMonster = {...this.currentMonster}
//using Object.assign() to create new object
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
let newMonster = Object.assign({},this.currentMonster);

然后只需更改适当的属性并将新对象推送到数组中。

//give new monster a name 
newMonster.name = this.currentMonster.name +" " + `${i+1}`;

//push the new monster on the array
this.monsters.push(newMonster);

【讨论】:

  • 100%!我现在明白我想做的是推送参考而不是副本,对吗?这种动态有术语吗?
  • 是的,您推送的是参考而不是副本。请参阅Is JavaScript a pass-by-reference or pass-by-value language? 以获取有关正在传递的主题的问答
  • @Timotronadony 是的,这个词是“复制”与“克隆”...欢迎来到 javascript 的黑暗面 :)
  • 我的上帝。谢谢大家,这会毁了我的脸。
【解决方案2】:

当你这样做时:

 this.monsters.push(this.currentMonster)

您没有将currentMonster 对象的副本推送到您正在推送对该对象的引用的数组。在这一点上,这意味着:

 this.monsters[0] === this.currentMonster

那么当你改变 name 属性时:

this.monsters[i].name = newName

你也在改变 currentMonster.name 属性

您可能想要做的是创建currentMonster 对象的副本并仅更改名称:

this.monsters.push({
     ...this.currentMonster,
     name: `${this.currentMonster.name} ${i+1}`
})

【讨论】:

    【解决方案3】:

    var arr = []; // create arry 
    var obj = {ima:"object"}; // create object
    arr.push(obj); // pass same object 3 times
    arr.push(obj);
    arr.push(obj);
    
    console.log(arr); // log arr 
    // will print : [
    // {
    //  /**id:2**/
    //    "ima": "changed object"
    //  },
    //  /**ref:2**/,
    //  /**ref:2**/
    // ]
    obj.ima = "changed object"; // change the object 
    
    console.log(arr); // log the array, notice that object inside the array will be modified
    
    arr[0].ima = "changed in the arr"; // then modify the object inside the array
    
    console.log(obj); // notice original object will be modified.
    
    arr.push(Object.assign({},obj)); // this is the copy or use ... operator in typescript
    
    console.log(obj);
    
    arr[1].ima = "something newer";
    
    console.log(obj); // "remains same"

    上面的代码与您在代码中所做的相同。您传递的是引用而不是复制的值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-14
      • 2010-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-05
      • 1970-01-01
      相关资源
      最近更新 更多