23

Let's say I have a simple class like this in fileA.js:

class foo {
    constructor(x) {
        this.name = x
    }

    fooMethod(x) {
        return x + 'hello';
    }
}

And I want to import and use fooMethod in fileB.js like this:

import { fooMethod } from './fileA';

class bar() {
    ...
    barMethod(x) {
        return fooMethod(x);
    }
}

How would I write the export in fileA to achieve this?

Rotareti
  • 49,483
  • 23
  • 112
  • 108
  • 1
    `export { foo.prototype.fooMethod as fooMethod }` might work. – gcampbell Jul 11 '16 at 13:33
  • How do you plan to invoke it? – Tamas Hegedus Jul 11 '16 at 13:34
  • @IlyaNovojilov no, this would export the class, not the bare method. – Lux Jul 11 '16 at 13:35
  • But as Lux has pointed out, it's probably better to find an alternative way of structuring it (prototype methods are meant to be called on something, not on their own). – gcampbell Jul 11 '16 at 13:38
  • @TamasHegedus I updated the question. – Rotareti Jul 11 '16 at 13:40
  • @le0m The interesting question is *why do you want to do this*? What is * fooMethod* doing that you want to call it without an object? Is it side effect free? On which object should it operate? – Lux Jul 11 '16 at 13:59
  • @Lux I have multiple modules/classes of type `bar` that share identical functionality. In order to NOT repeat myself in each one of those classes I want to move the identical parts to DIFFERENT parent classes such as `foo`. Since I can only `extend` a class with ONE other class I'm limited and I'm looking for other ways of implementation. The shared methods are used in a template a lot so they need to be as short as possible. `import {fooMethod) from ...` would give straight access to `fooMethod` w/o calling `className.fooMethod`. Hope it makes sense. – Rotareti Jul 11 '16 at 14:26
  • @le0m I've edited my answer. Check it out. – Lux Jul 11 '16 at 17:13

5 Answers5

17

You would have to export it on the prototype. But remember that if you do that you won't call the function in the class/object context:

export foo.prototype. fooMethod

However I would recommend you to not to do so.


Okay, due to your comment you want a good way to have a common functionality for two classes, that don't extend the same base class. One simple way is to import a utility function from two classes:

foo.js

export function foo() {
  return this.name;
}

a.js

import {foo} from 'foo';
export class A extends BaseA {
  foo() {
    foo.apply(this, arguments);
  }
}

b.js

import {foo} from 'foo';
export class B extends BaseB {
  foo() {
    foo.apply(this, arguments);
  }
}

This is a good pattern and works well for a single function, but has limits if you want to apply more complex functionality. A good way to achieve this is a mixing pattern:

foo.js

export default superClass => class extends superClass {
  foo() {
    return this.name;
  }
};

a.js

import foo from 'foo';
export class A extends foo(BaseA) {
  ..
}

b.js

import foo from 'foo';
export class B extends foo(BaseB) {
  ..
}

This will make your mixing create a new anonymous class between your class 'A'/'B' and 'BaseA'/'BaseB', which provides the common function foo.

Lux
  • 17,835
  • 5
  • 43
  • 73
  • So the only way to get `fooMethod` in `fileB` with the context of class `foo` is to import the entire `foo` class and call `fooMethod` from it? – Rotareti Jul 11 '16 at 13:50
  • Well, you would need a object to have a context, not a class. So you would need to initialize an object. Maybe create a singleton? – Lux Jul 11 '16 at 13:52
  • The mixing pattern looks very interesting! Could I extend a class with multiple foo-like classes this way: `class A extends fooOne(fooTwo(Base))`? – Rotareti Jul 11 '16 at 23:45
9

You have to export it as a separate variable/constant, like this:

class Foo {
  fooMethod() {};
}

export const fooMethod = Foo.prototype.fooMethod;

See Babel/repl

Edit

It turns out in comments that you don't really need an instance method (You don't use this). I would just define and use a regular function:

export function fooMethod(x) {
    return x + 1;
}
Tamas Hegedus
  • 28,755
  • 12
  • 63
  • 97
9

You can export and import class methods by instantiating the class which obviously turns it into an object and then exporting each method by destructuring them from the new instantiated object check code example below.

Destruct and export object methods like this:

class foo {
  doSomething() {
    // some stuffs
  }

  doAnotherThing() {
    // do something else
  }

}

export const { doSomething, doAnotherThing } = new foo()

Then in your file where you want to import the methods do this:

import { doSomething, doAnotherThing } from '../class/file/directory'

doSomething() // calls the method

I hope this helps

Chiano
  • 91
  • 1
  • 2
3

This is how I usually solve exports of functions in helper classes. Using a singleton of a helper class is preferably and that's why it works fine here. Not sure if you're okay with creating a singleton, but it works fine.

class foo {
  constructor(x) {
    this.name = x
  }

  internalFooMethod(x) {
    return x + 'hello';
  }
}

const singleton = new foo();
export default singleton;

export function fooMethod(x) {
  return singleton.internalFooMethod
}

And then import and call it in fileB.js:

import { fooMethod } from './fileA';

class bar() {
    barMethod(x) {
        return fooMethod(x);
    }
}

Of course we can import the default class foo as well as the exported function:

import FooSingleton, { fooMethod } from './fileA';
Calsal
  • 1,375
  • 14
  • 25
-3

It's better you don't export methods. Follow this.

fileA

export class foo {
    constructor(x) {
        this.name = x
    }

    fooMethod(x) {
        return x + 'hello';
    }
}

app.component.ts

import { Component } from '@angular/core';
import { foo } from './fileA';

@Component({
  moduleId: module.id,
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css']
})
export class AppComponent {
  title = 'app works!';
  constructor(private fooClass: foo){
      this.fooClass.fooMethod('');
  }
}
  • 6
    There's no indication in the question that the OP is using TS or Angular, so your example has a lot of noise. On top of that, you don't explain why this is better and have missed the fact `fooMethod` can be static. – ssube Jul 11 '16 at 15:36