1

I've ran into a little problem while refactoring my stuff...

Problem:

I got a single Class file with 1.1k lines and ~10 methods

What I'd like to do (tl;dr):

Outsource each method into it's own file, module.export them, have a helper method/file requiring all of them, having my class import only this helper file and adding all methods back to my class so that class.method calls them properly.

What I'd like to do (with a little extra)

Aight - Status is this... I've got a class

myclass.js

class MyClass{
  constructor(a,b){
    this.a = a
    this.b = b
  }

  methodOne(){
  console.log(this.a)
  *100 lines of code*
  }

  methodTwo(){
  *100 lines of code*
  }

  methodThree(){
  *100 lines of code*
  }
   .... and so on
}

What I'd like to have:

methodOne.js

 module.exports.methodOne = () => {
   console.log(this.a) 
   99 more lines of Code
 }

methodTwo.js

 module.exports.methodTwo = () => {
    100 lines of Code
 }

...and so on

functions_injector.js - a little pseudo for length

const fs = require('fs')
const functions = {}
const functionsInjector = () => {
 fs.readDir('./functions/', (err, files) => {
   files.each((fileName) => {
   functions[fileName.split('.')[0]] = require('./functions/'+fileName)       
 }
}
functionsInjector()
module.exports = functions

myclass.js

const functions = require('./functions_injector')
class MyClass {
  constructor(a,b) {
    this.a = a
    this.b = b
 }
}

const funcNames = Object.keys(functions)
const funcs = Object.values(functions)
funcNames.forEach((funcName, idx) => {
  MyClass.prototype[funcName] = funcs[idx]
}

const tryMe = new MyClass('a', 'b)
const plsWork = tryMe.methodOne()
console.log(plsWork)

Expected : 'a'

Buuut sadly the reality is: undefined

Digging a little deeper by calling console.log(this) in methodOne.js returns {methodOne: [Function]) what kinda makes sense. But since this results by calling

const tryMe = new MyClass()
tryMe.methodOne()

I can atleast confirm, that I can access the methods via the class, now they only need to access the same this

The Code's a little simplified.. The real one is fully async/await and such, but I didn't wanna bother you with even more code.

The construction of the injector and passing it over to myClass is working, I can access the Object of {name:function} pairs.. all I need is a little hint as to how to add the methods to my class in a way that they're methods of the class.

Any help much appreciated! Cheers

PS: I probably could make each method it's own class and extend and extend and extend... But since I'd like to have each method in it's own file (I know this is a question of style, but eh), I really don't wanna go down that road...

I'm still thinking about if I did something wrong on the module.exports side of the methods. If I did, I got no absolutely no clue :D

Rockbob
  • 135
  • 1
  • 2
  • 11
  • 1
    Don't use arrow functions, use a normal function. Arrow functions have a lexically bound `this` context, so it will never refer to your object - a normal function will set `this` upon execution. So, simply change `module.exports.methodOne = () => {` to `module.exports.methodOne = function() {` – VLAZ Oct 07 '19 at 14:26
  • I've tried that before. Lets say I add a method in myClass, simply logging Object.keys(this), rewrite methodOne to use normal function declaration and to log Object.keys(this) there as well... myClass logs ['a','b], methodOne still undefined :( Edit: But it brings me closer.. While console.log(this) with arrow functions returns [methodOne: [Function]], console.log(this) with function declaration returns [Function: MyClass]. But I still can't access the instance *this* – Rockbob Oct 07 '19 at 14:38
  • Nope, ignore that comment... I just had some artifacts by trying to .bind() while playing around with normal function declaration... Works, cheers! – Rockbob Oct 07 '19 at 14:56
  • 1
    Apart from the issue with arrow function syntax, importing a whole method definition is the wrong way to go. Your underlying problem really is the 100 LOC methods. Refactor them into smaller helper functions, call the helper functions from the methods that are defined in the `class` body (and pass them all the values as individual arguments, don't pass the whole instance). Then put the helper functions in their individual modules. – Bergi Oct 07 '19 at 18:22

1 Answers1

1

This method works, but arrow functions don't bind this and arguments so it cannot access the this.a or this.b

AND, You have a typo in your MyClass it's constructor.

Simple Proof of concept: Simple Code example:

const methodOne = function () {
  console.log(this.a);
}

class MyClass {
  constructor(a, b) {
    this.a = a;
    this.b = b;
  }
  m2() {
    console.log(this.b);
  }
}
MyClass.prototype.methodOne = methodOne;

const tryMe = new MyClass('I work', 'I work too');
tryMe.methodOne()
tryMe.m2();

Output:

I work
I work too
Aritra Chakraborty
  • 12,123
  • 3
  • 26
  • 35
  • 1
    Cheeerssss... I had tried that in the past but it seems like I was trying to bind() some funny things as well.. Gnahhhh. Thanks! – Rockbob Oct 07 '19 at 14:55