rmehlinger
rmehlinger

Reputation: 1076

Utility functions to instantiate instance of a CoffeeScript class that extends a pre-existing object

So I've been playing with prototypal inheritance in CoffeeScript, and in particular with how one can go about writing CoffeeScript classes that inherit from a particular object, rather than another class, similar to Crockford's object function. Essentially what I'd like to do is to write a class that can inherit from a particular object passed in to its constructor. Unfortunately, I believe this may be impossible without resort to setPrototypeOf, which, given the rather alarming warnings about it, I'd rather not do. Instead I am probably going to settle for a function that can do something similar. Below are two possibilities:

a = {foo: 1}

class Example
  constructor: (@bar) ->

extendObject = (parent, Class, args...) ->
  F = (anon...) -> Class.apply(@, anon)
  F:: = Object.create parent
  F::constructor = Class
  new F args...

extendObjectMaker = (parent, Class) ->
  F = (anon...) -> Class.apply(@, anon)
  F:: = Object.create parent
  F::constructor = Class
  F

maker = extendObjectMaker a, Example

test1 = extendObject a, Example, 2
test2 = new maker 2

Now, I greatly prefer the second approach, since essentially what it is returning is a new class, which you can then use regular constructor syntax with. There's just one problem: while objects created using extendObject correctly identify as Examples, objects created using the constructor returned by extendObjectMaker identify as Fs, and are not instances of Example.

console.log test1 instanceof Example # True
console.log test2 instanceof Example # False

Given that these functions use almost exactly the same code, I'm having difficulty figuring out just why they're exhibiting different behavior. So, does anyone know why test2 is not showing up as an Example, and what I need to change to make it do so?

Upvotes: 1

Views: 119

Answers (1)

Aleph Aleph
Aleph Aleph

Reputation: 5395

Take a look at the CoffeeScript source code: http://coffeescript.org/v1/annotated-source/nodes.html#section-60.

CoffeeScript treats constructor calls differently depending on whether they are called with a splat (args...) or without one.

Your code will give the desired result if you either invoke the extendObjectMaker with new maker [2]... or re-write your function as follows:

extendObjectMaker = (parent, Class) ->
  F = (anon...) -> Class.apply(@, anon)
  F:: = Object.create parent
  F::constructor = Class
  (args...) -> new F args...

Upvotes: 2

Related Questions