Reputation: 4173
I would like to have a class where I can specify "Instance a1 of A, you will call the function computeValue() of the specific instance b1 of B when you need the value". I need to specify which method of which instance will be used by this instance.
So far I found two solutions :
The eval()
solution :
class A {
constructor(funcToCall) {
this.funcToCall = funcToCall;
}
displayValue() {
console.log(eval(this.funcToCall));
}
}
class B {
constructor(value) {
this.value = value;
}
computeValue() {
return this.value;
}
}
var b1 = new B(1);
var a1 = new A("b1.computeValue()");
a1.displayValue();// Displays "1", okay
The function.call()
solution :
class A {
constructor(funcToCall, instanceToCallItOn) {
this.funcToCall = funcToCall;
this.instanceToCallItOn = instanceToCallItOn;
}
displayValue() {
console.log(this.funcToCall.call(this.instanceToCallItOn));
}
}
class B {
constructor(value) {
this.value = value;
}
computeValue() {
return this.value;
}
}
var b1 = new B(1);
var a1 = new A(b1.computeValue, b1);
a1.displayValue(); // Displays "1", okay
So to me the eval()
solution seems very dirty and the function.call()
seems better.
Which solution is the best ? Is there a more elegant solution to this problem ?
Upvotes: 0
Views: 64
Reputation: 781004
Using functions should almost always be preferred over eval()
. You can simplify the second method by using .bind()
, so you don't need to pass the function and instance separately.
class A {
constructor(funcToCall) {
this.funcToCall = funcToCall;
}
displayValue() {
console.log(this.funcToCall());
}
}
// class B is the same as yours
var b1 = new B(1);
var a1 = new A(b1.computeValue.bind(b1));
a1.displayValue();
Or if you still prefer to pass the instance separately, you can use .bind()
in the constructor:
class A {
constructor(funcToCall, instance) {
this.funcToCall = funcToCall.bind(instance);
}
displayValue() {
console.log(this.funcToCall());
}
}
Upvotes: 1
Reputation: 664538
Yes, that eval
thing is very dirty and won't even work if b1
is not in the proper scope. Using call
is fine, but you can do better:
Pass a combination of instance and methodname:
class A {
constructor(instance, methodName) {
this.instance = instancen;
this.methodToCall = methodName;
}
displayValue() {
console.log(this.instance[this.methodToCall]());
}
}
var a1 = new A(new B(1), "computeValue);
Pass a function that does the method call and whatever else it needs on its own:
class A {
constructor(funcToCall) {
this.funcToCall = funcToCall;
}
displayValue() {
console.log(this.funcToCall());
}
}
var b1 = new B(1);
var a1 = new A(() => b1.computeValue());
// or: new A(b1.computeValue.bind(b1))
// or anything else
Upvotes: 1