10

Sorry if question is too simple, but I'm missing something here. Just switched an ES5 module that looked like:

module.exports = {
  func1: function(a, b) {...},
  func2: function(a, b) {...}
};

To an ES6 class that looks like this:

export default class {
  func1(a, b) {...}
  func2(a, b) {...}
}

And all was well: in both cases I could export mod from 'module'; and call mod.func1(a, b) and mod.func2(a, b).

However, I have a function that recieves a module function to call:

var caller = function(func, val1, val2) {
  let a = something(val1);
  let b = something(val2);
  return func(a, b);
};

When I call caller(mod.func1, x, y) I get the desired result with the first implementation, but an undefined is not a function with the second.

Printing out the value of mod.func1 returns [Function] in both cases, but clearly something else is returned from an ES6 class.

What am I doing wrong, and how can I get a class function I can call in another function?

Update: with the second implementation, I forgot to add the instantiation code:

import Mod from 'module';
var mod = new Mod();
Traveling Tech Guy
  • 27,194
  • 23
  • 111
  • 159
  • 1
    I really doubt that `mod.func1(a, b)` works with the exported class. – Bergi Aug 01 '15 at 21:08
  • Forgot the instantiation code - now added. Thanks. – Traveling Tech Guy Aug 01 '15 at 21:38
  • 1
    Hm, passing the `mod.func1` method as a function to somewhere else requires you to deal with the [`this` context in callbacks](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback) problem, but that shouldn't change when switching from an object to a class instance either. Can you show us the body of your function? – Bergi Aug 01 '15 at 21:44

2 Answers2

7
class MyClass {
  method(args) {}
}

is short hand for:

function MyClass() {}
MyClass.prototype.method = function(args){};

What you are looking for is a static method on the constructor, which in ES{3,5} is done this way:

function MyClass() {}
MyClass.method = function(args){};

and in ES6 is done with the static modifier:

export default class {
  static func1(a, b) { /* stuff */ }
  static func2(a, b) { /* stuff */ }
}

However, you can use short-hand methods even in an object, so using a normal object is clearer in the general case:

export default {
  func1(a, b) {/* stuff */},
  func2(a, b) {/* stuff */}
}

Why aren't prototype methods available on the constructor?

Because it's not that way in ES3 or ES5:

function MyClass() {};
MyClass.prototype.method = function(args) {};

MyClass.method  // undefined

var instance = new MyClass();
instance.method  // function(args) {}

Creating an instance is necessary to have access to methods on the prototype.

Sean Vieira
  • 155,703
  • 32
  • 311
  • 293
  • Thanks for the suggestion. But if `class` is just sugar, why the difference in function accessibility? – Traveling Tech Guy Aug 01 '15 at 21:42
  • Thanks Sean. I updated my question to show the instantiation code - but that didn't work either :(. BTW, if you do want to call a method on the class name, you could add `static` at the function definition. – Traveling Tech Guy Aug 02 '15 at 03:02
  • Correct - I'm not able to reproduce this in babel - I get the expected behavior when I instantiate the class. Any more details on how you are compiling / running this (or a more detailed snippet might help too). – Sean Vieira Aug 02 '15 at 03:21
  • I'm using Babel to transpile, and the function I had a problem passing a class function into a Passport middleware. The code is too complex to post. But do you say you've managed to get an example like mine working? If so, it must be something I've done wrong. – Traveling Tech Guy Aug 02 '15 at 06:03
4

Why did you switch to a class construct (which is a bit more than syntactic sugar for a constructor and a prototype with the methods)? There is no reason not to use an object literal like you did before - you can use method syntax in there as well:

export default {
  func1(a, b) {...},
  func2(a, b) {...}
};

Instead of exporting an object with "static" methods, it would be more reasonable to use named exports here though:

export function func1(a, b) {...}
export function func2(a, b) {...}

which you could import by import * as mod from 'module' if you like to use mod as a namespace.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 2
    I don't get why everybody thinks they have to use as many ES6 features as possible even if it doesn't make sense. Same for arrow functions... and "suddenly" it does not work as expected. – Felix Kling Aug 01 '15 at 21:09
  • 6
    I don't have a problem with it not working - I want to understand why it doesn't work. – Traveling Tech Guy Aug 01 '15 at 21:40