开发者

Extend class and pass all constructor arguments to super

How would you extend a class using CoffeeScript, but have the construction 开发者_如何学运维arguments passed to super?

Eg:

class List extends Array
    # Some other stuff to make it work...

list = new List(1,2,3)

console.log list
[1, 2, 3]


In general, this would work without additional code; the parent constructor is used unless expressly overridden:

class A
  constructor: ->
    console.log arg for arg in arguments

class B extends A

new B('foo') # output: 'foo'

And the problem isn't that Array doesn't have a constructor method:

coffee> Array.constructor
[Function: Function]

The problem is just that Array is just plain weird. While arrays are "just objects" in principle, in practice they're stored differently. So when you try to apply that constructor to an object that isn't an array (even if it passes the instanceof Array test), it doesn't work.

So, you can use Acorn's solution, but then you may run into other problems down the road (especially if you pass a List to something that expects a true array). For that reason, I'd recommend implementing List as a wrapper around an array instance, rather than trying to use inheritance from a native object type.

While we're on the subject, one very important clarification: When you use super by itself, that does pass all arguments! This behavior is borrowed from Ruby. So

class B extends A
  constructor: ->
    super

will pass along all arguments to A's constructor, while

class B extends A
  constructor: ->
    super()

will invoke A's constructor with no arguments.


class List extends Array
    constructor: ->
        @push arguments...

    toString: ->
        @join('-')

list = new List(1, 2)

list.push(3)

list.toString()

=>

'1-2-3'


Using extends in CoffeeScript expects the superclass to be in CoffeeScript too. If you're using a non-CS class, e.g. Array in the original question, then you may encounter problems.

This solved the general case for me. It's a bit of a hack because it uses _super which probably isn't intended to be used in the compiled JS.

class MyClass extends SomeJsLib

  constructor: ->
    _super.call @, arg1, arg2

Or if you just want to pass thru arguments from the caller:

class MyClass extends SomeJsLib

  constructor: ->
    _super.apply @, arguments


In my exploration of javascript I required a generic way to create a class with a dynamic number of constructor arguments. As mentioned this won't work for array as far as I know, it will only work for coffee-script style classes.

Calling a specific function with a dynamic number of arguments is easy enough through .apply

args = [1, 2, 3]
f = measurement.clone

f.apply measurement, args

A class can extend a class saved in a variable. As a result we can write a function that returns new sub-classes.

classfactory = (f) ->
    class extension extends f

Putting it all together we can create a function that returns new sub-classes in which we apply arguments to the super class's constructor.

classwitharguments = (f, args) ->
    class extension extends f
        constructor: () ->
            extension.__super__.constructor.apply @, args

To use this new factory

args = [1, 2, 3]
instance = new (classwitharguments Measurement, args)

Thoughts? Comments? Suggestions? Limitations I didn't think about? Let me know.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜