Reputation: 4352
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;
}
Upvotes: 1
Views: 204
Reputation: 129
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.
Upvotes: -1
Reputation: 96
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.
Upvotes: 3