Rix
Rix

Reputation: 1768

Define a class that new a function in CoffeeScript

I want to use the 'class' syntax to create a class, and when it news an instance, the instance can be directly used as a Function.

class Foo
  constructor: (@bar) ->
  baz: ->
    console.log 'baz'
  ...

f = new Foo 'bar'
f() # runs () -> console.log @bar
f.baz() # 'baz'

Here is a JavaScript solution but I cannot reproduce it in CoffeeScript using class syntax.

Upvotes: 2

Views: 1399

Answers (4)

hpaulj
hpaulj

Reputation: 231355

Here's an variation on Bergi's answer:

class Foo
  constructor: (@bar) ->
    foo = () =>
      console.log @bar
    foo.baz = ->
      console.log 'baz'
    return foo
f = new Foo 'bar'
f()
f.baz()

This may just be using class as a wrapper, much as do() does. f is { [Function] baz: [Function] }. Also Foo 'bar' (without the new), produces the same thing.

Upvotes: 0

hpaulj
hpaulj

Reputation: 231355

I don't think you can write a Coffeescript class which compiles to that Javascript (or something close). The Coffeescript class insists on 2 things:

It ends the class body with return AwesomeObject;

If I put a return bar in the class body, it objects with error: Class bodies cannot contain pure statements.

The linked Javascript model is:

var AwesomeObject = (function() {
    var AwesomeObject = function() {...};
    ...
    return function() {
      var o = new AwesomeObject();
      ...};
})();

It defines an AwesomeObject constructor internally, but returns a different function. This is clearer if the internal name is changed to AwesomeObject1. It functions the same, but there is no way of accessing AwesomeObject1 directly.

Also AwesomeObject() and new AwesomeObject() return the same thing.

{ [Function]
  whatstuff: 'really awesome',
  doStuff: [Function] }

The compiled Coffeescript (for class AwesomeObject...) instead is:

AwesomeObject = (function() {
  function AwesomeObject() {...}
  ...
  return AwesomeObject;
})();

P.S. https://github.com/jashkenas/coffee-script/issues/861 Coffeescript issue discussion on new Foo() versus Foo() syntax. Consensus seems to be that while new-less calls are allowed in Javascript for objects like Date, it isn't encouraged for user defined classes. This is interesting, though not really relevant to the question here.

Upvotes: 3

Bergi
Bergi

Reputation: 664297

This is what you're looking for:

class Foo
  constructor: (@bar) ->
    f = -> console.log bar
    for v, k of @
      f[v] = k
    return f
  baz: ->
    console.log 'baz'

f = new Foo 'bar'
f() # runs () -> console.log @bar
f.baz() # 'baz'

Notice that this solution does not return a callable object which inherits from Foo.prototype (which is impossible), but that it does return a Function object in which some properties are mixed in.

A better pattern would be not to return a callable function object, but to return a standard object instance that has a call or execute method.

Upvotes: 0

phenomnomnominal
phenomnomnominal

Reputation: 5515

How about something like this:

class Foo
  constructor: (@bar) ->
    return => console.log @bar

f = new Foo 'bar'
f()

Upvotes: 0

Related Questions