skip to Main Content

So, I have two classes service-class & entity-class with private constructor & static async method, for creating new instance of class. My service-class create & call new entity-class instance and modified it with its properties.

Example | This is NOT NEST.JS code:

class Service {
   run() {
     const entity = Entity.createNewEntity(args);

     await entity.methodMother();

     const getMyProps1Back = entity.props1();

     // is [ ] empty array, not modified after methodChild
     console.log(getMyProps1Back);

   }
}

Each method of my entity is covered with bind decorator from npm: bind-decorator module

class Entity {
  this.props1! Array<Record<Type>>;
  this.props2 = new Map([]);


  private constructor(someArgs: any) {
     // some stuff
     this.props1 = [];  
  }

  get getProps1() {
    return this.props1;
  }

  static async createNewEntity() {
     const entity = new Entity();
     // blah-blah work here
     return entity;
  }

  @bind
  public async methodMother() {
    this.props1.push({ some: stuff });

    // 

    this.methodChild();
    // method logic
  }

  @bind
  private methodChild() {
     // adding more elements, or overwriting the array
     this.props1 = [test1, test2, test3];
  }
}

So my questions here are about explaining why context is lost during calling of methodChild within the methodMother and how is my getter return an unmodified array of props1?

## How does it work, and what should I do to avoid it?

Passing an array like argument and returning it back, like this? Or something else, like makign them anonymous?

  @bind
  private methodChild(props1 : Array<OfProps1>) {
     // adding more elements, or overwriting the array
     props1 = [test1, test2, test3];

     return arg;
  }

2

Answers


  1. The code you’ve sent seems to work fine without the @bind decorator (After some clean-up):

    type KeyType = any
    type ValueType = any
    
    class Entity {
      props1!: Record<KeyType, ValueType>[];
      props2 = new Map([]);
    
    
      private constructor() {
        // some stuff
        this.props1 = [];
      }
    
      getProps1() { // <-- NOTE: Removed the `get` from here
        return this.props1;
      }
    
      static async createNewEntity() {
        const entity = new Entity();
        // blah-blah work here
        return entity;
      }
    
      public async methodMother() {
        this.props1.push({ some: 'stuff' });
    
        this.methodChild();
      }
    
      private methodChild() {
        this.props1 = [
          ...this.props1,// existing values
    
          { some: 'other stuff' },
          { evenMore: 'other stuff' },
          { andMore: 'other stuff' }
        ]
      }
    }
    

    And when you run it:

    class Service {
      async run() {
        const entity = await Entity.createNewEntity();
    
        await entity.methodMother();
    
        const getMyProps1Back = entity.getProps1();
    
        console.log(getMyProps1Back);
      }
    }
    

    You get a nice Output:

    [
      {
        some: "stuff",
      },
      {
        some: "other stuff",
      },
      {
        evenMore: "other stuff",
      },
      {
        andMore: "other stuff",
      }
    ]
    

    This is based on the code you have given.

    Login or Signup to reply.
  2. What you are looking at needs an explanation aimed at both ideas:

    • The clock is not actually misplaced inside methodChild. This has been
      taken care of by the @bind decorator. That can’t be the problem.

    • The real problem is in how you’re modifying props1 in methodChild:

      this.props1 = [test1, test2, test3];

      And this line transfers the value of the original props1 array to a brand new Replacement an array, not just changing the existing one

    • Meanwhile, your getter getProps1 is likely returning a reference to
      the original props1 array, which hasn’t been modified:

      get getProps1() { return this.props1; }

      This getter was defined before methodChild ran, so it’s still pointing to the original (empty) array.

    To fix this, you have a few options:

    • Modify the existing array instead of reassigning:

      @bind
      private methodChild() {
        this.props1.length = 0;  // Clear the array
        this.props1.push(test1, test2, test3);  // Add new elements
      }
      
    • Update the getter to always return the current value of props1:

      get getProps1() {
        return this.props1;
      }
      
    • If you really have to reassign props1 then use a method instead
      of a getter.

      getProps1() {
        return this.props1;
      }
      

      Then call it asentity.getProps1() instead of entity.props1.

    As for your suggestion of passing the array as an argument:

    @bind
    private methodChild(props1: Array<OfProps1>) {
      props1 = [test1, test2, test3];
      return props1;
    }
    

    This wouldn’t solve the problem because JavaScript passes arrays by reference. Reassigning the parameter props1 inside the method won’t affect the original this.props1. You’d need to do something like:

    @bind
    private methodChild() {
      const newProps1 = [test1, test2, test3];
      this.props1.length = 0;
      this.props1.push(...newProps1);
    }
    

    This modifies the existing array in place, ensuring that all references to this.props1 see the changes.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search