In order to set up a Socket.IO client, I have a bunch of methods looking like this:
myobject.prototype.A = function (callback) {
this.foo('a', null, callback);
}
myobject.prototype.B = function (bar, callback) {
this.foo('b', { bar }, callback);
}
myobject.prototype.C = function (baz, qux, callback) {
this.foo('c', { baz, qux }, callback);
}
The content of this.foo
is unimportant, but it takes 3 parameters: a string, an object built from the calling method parameters, and a callback method.
I'd like to have the methods set up in a single place. I'd like to have something looking like this:
// I'm not sure what form the args should take
const methods = {
A: { socketName: 'a', args: [ ] },
B: { socketName: 'b', args: [ 'bar' ] },
C: { socketName: 'c', args: [ 'baz', 'qux' ] }
};
for (let m in methods) {
const mData = methods[m];
this.prototype[m] = function (what_do_I_put_here_?, callback) {
// how do I form "otherArgs" ?
this.foo(mData.socketName, otherArgs, callback);
}
}
I think I'll have to look to destructuring assignments but I'm not sure how to use them in this case.
You could do that utilizing closures and an array function:
"use strict"
class Test {
createDynFoo(name, propertyNames = []) {
// return an arrow function (ensures that this is still the obj)
return (x, ...args) => {
let obj = null; // set obj to null as default
if (args.length > 0) {
// if we have additional aguments to x we create an obj
obj = {};
// map the additional arguments to the property names
propertyNames.forEach((value, idx) => {
obj[value] = args[idx]
})
}
// call the actual foo function
return this.foo(name, x, obj)
}
}
foo(name, x, obj) {
console.log(`${name} ${x}`)
console.dir(obj);
}
}
let test = new Test();
let tiggerForA = test.createDynFoo('a');
let tiggerForB = test.createDynFoo('b', ['y']);
let tiggerForC = test.createDynFoo('c', ['y', 'z']);
tiggerForA(1);
tiggerForB(1, 2);
tiggerForC(1, 2, 3);
If you really need it as member functions you could do:
"use strict"
class Test {
constructor() {
this.A = this.createDynFoo('a');
this.B = this.createDynFoo('b', ['y']);
this.C = this.createDynFoo('c', ['y', 'z']);
}
createDynFoo(name, propertyNames = []) {
// return an arrow function (ensures that this is still the obj)
return (x, ...args) => {
let obj = null; // set obj to null as default
if (args.length > 0) {
// if we have additional aguments to x we create an obj
obj = {};
// map the additional arguments to the property names
propertyNames.forEach((value, idx) => {
obj[value] = args[idx]
})
}
// call the actual foo function
return this.foo(name, x, obj)
}
}
foo(name, x, obj) {
console.log(`${name} ${x}`)
console.dir(obj);
}
}
let test = new Test();
test.A(1);
test.B(1, 2);
test.C(1, 2, 3);
If it is only about member functions you could get rid of the the arrow function like this:
"use strict"
function createDynFunction(classObj, targetFunctionName, newFunctionName, name, propertyNames = []) {
// create a new function and assigned it to the prototype of the class
classObj.prototype[newFunctionName] = function(x, ...args) {
let obj = null; // set obj to null as default
if (args.length > 0) {
// if we have additional aguments to x we create an obj
obj = {};
// map the additional arguments to the property names
propertyNames.forEach((value, idx) => {
obj[value] = args[idx]
})
}
// call the actual foo function
return this[targetFunctionName](name, x, obj)
}
}
class Test {
foo(name, x, obj) {
console.log(`${name} ${x}`)
console.dir(obj);
}
}
createDynFunction(Test, 'foo', 'A', 'a');
createDynFunction(Test, 'foo', 'B', 'b', ['y']);
createDynFunction(Test, 'foo', 'C', 'c', ['y', 'z']);
let test = new Test();
test.A(1);
test.B(1, 2);
test.C(1, 2, 3);
As I don't know the exact use case, it is hard to come up with a solution that exactly matches the needs. But based on the shown code, you should get an idea how this can be achieved.