The title is probably worded horribly, but I'm not sure how to articulate what I'm trying to do here.
Essentially what I have is a class that contains two methods:
- An object factory class function
objFactory
that returns an object that contains three properties (value1,value2,value3) and another function bound to the object. I.e.myObj = {value1: 1, value2: 2, value2: 3, func()}
- Another class function
changeValueProperties
that will create values 1-3 based on an input value formyObj
.
The user calls the factory method and an object is returned. The intent is that the user doesn't modify values 1-3 directly in the returned object, rather they call the built in method that computes those values and updates them on the object for the user. i.e. changeValueProperties
is suppose to be a blackbox to the end user, they don't know how to calculate value1, value2, value3 for themselves.
The main issue here being the 'this' keyword. 'this' is referring to the MyTestClass, when I really want it bound to the returned object, so that its internal properties can be modified. I imagine something like this can be achieved via the call/apply/bind methods, but I'm not quite clear how to achieve that in this particular context. Especially when the updateValues
method will use one of the class's own methods to do the computation.
I'm also open to alternative suggestions in terms of architecture. I realize this probably isn't kosher and there is probably a better method to implement the strategy I'm going for.
class MyTestClass {
dummyData;
constructor() {
this.dummyData = 100;
}
changeValueProperties(value) {
return {
value1: value*1,
value2: value*2,
value3: value*3
}
}
objFactory(value, ..other parameters) {
let computedValues = this.changeValueProperties(value);
let updateValues = (newValue) => {
let computedValues = this.changeValueProperties(newValue);
// This is where updateValues needs to update
// values 1-3 in myReturnedObj that has been returned to the calling user.
// this keyword can't be used, because it is bound to MyTestClass and not
// myReturnObj
this.value1 = computedValues.value1;
this.value2 = computedValues.value2;
this.value3 = computedValues.value3;
}
let myReturnObj = {
value1: computedValues.value1,
value2: computedValues.value2,
value3: computedValues.value3,
updateValues: updateValues
}
return myReturnObj
}
}
const myClass = new MyTestClass();
let myObj = myClass.objFactory(10,...other parameters for object generation);
// {value1: 10, value2: 20, value3: 30, ...}
myObj.updateValues(20);
// should return {value1: 20, value2: 40, value3: 60, ...}
CodePudding user response:
There is a lot going on here, first of all, I think the arrow function does not bind this
the way you intend. I recommend using a function
instead.
function updateValues(newValue) { /* ... */ }
CodePudding user response:
So I ended up solving this after beautifulcoder pointed out that this
does not behave the same way as a normal function. If you are stubborn and want to solve the problem using arrow functions however, you can use the following refactored code:
objFactory(value, ..other parameters) {
let computedValues = this.changeValueProperties(value);
let myReturnObj = {
value1: computedValues.value1,
value2: computedValues.value2,
value3: computedValues.value3,
updateValues: (newValue) => {
let computedValues = this.changeValueProperties(newValue);
myReturnObj.value1 = computedValues.value1;
myReturnObj.value2 = computedValues.value2;
myReturnObj.value3 = computedValues.value3;
}
}
return myReturnObj
}
You can reference the object definition inside the object itself.
CodePudding user response:
It seems that you want this
in updateValues
to refer to two different objects. You have to decide on one of them, or neither.
To use neither, refer to the objects through variables:
objFactory(value) {
const computedValues = this.changeValueProperties(value);
const myTest = this;
const myReturnObj = {
...computedValues,
updateValues(newValue) {
const newComputedValues = myTest.changeValueProperties(newValue);
// ^^^^^^
Object.assign(myReturnObj, newComputedValues);
// ^^^^^^^^^^^
};
return myReturnObj;
}
This uses the old var self = this
pattern [1][2][3].
Now you can either
make
updateValues
a method that usesthis
to refer to themyReturnObj
:objFactory(value) { const computedValues = this.changeValueProperties(value); const myTest = this; return { ...computedValues, updateValues(newValue) { const newComputedValues = myTest.changeValueProperties(newValue); Object.assign(this, newComputedValues); // ^^^^ }; }
or make
updateValue
an arrow function so that it usesthis
from its parent scope:objFactory(value) { const computedValues = this.changeValueProperties(value); const myReturnObj = { ...computedValues, updateValues: (newValue) => { const newComputedValues = this.changeValueProperties(newValue); // ^^^^ Object.assign(myReturnObj, newComputedValues); }; return myReturnObj; }