Расширьте класс и передайте все аргументы конструктора супер

Как бы вы расширили класс, используя CoffeeScript, но аргументы конструкции переданы супер?

Например:

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

list = new List(1,2,3)

console.log list
[1, 2, 3]

Ответ 1

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

    toString: ->
        @join('-')

list = new List(1, 2)

list.push(3)

list.toString()

= >

'1-2-3'

Ответ 2

В общем, это будет работать без дополнительного кода; родительский конструктор используется, если явно не переопределяется:

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

class B extends A

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

И проблема не в том, что у массива нет метода constructor:

coffee> Array.constructor
[Function: Function]

Проблема в том, что Array просто странно. Хотя массивы являются "просто объектами" в принципе, на практике они хранятся по-разному. Поэтому, когда вы пытаетесь применить этот конструктор к объекту, который не является массивом (даже если он проходит тест instanceof Array), он не работает.

Итак, вы можете использовать решение Acorn, но тогда вы можете столкнуться с другими проблемами в будущем (особенно если вы передадите List тому, что ожидает истинный массив). По этой причине я рекомендую внедрить List в качестве оболочки вокруг экземпляра массива, вместо того, чтобы пытаться использовать наследование из собственного типа объекта.

Пока мы находимся в теме, одно очень важное разъяснение. Когда вы используете super самостоятельно, это действительно все аргументы! Такое поведение заимствовано у Ruby. Так

class B extends A
  constructor: ->
    super

передаст все аргументы конструктору A, а

class B extends A
  constructor: ->
    super()

будет вызывать конструктор A без аргументов.

Ответ 3

Использование extends в CoffeeScript ожидает, что суперкласс также будет в CoffeeScript. Если вы используете не-CS-класс, например. Array в исходном вопросе, тогда вы можете столкнуться с проблемами.

Это разрешило мне общий случай. Это немного хак, потому что он использует _super, который, вероятно, не предназначен для использования в скомпилированном JS.

class MyClass extends SomeJsLib

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

Или если вы просто хотите передать аргументы от вызывающего:

class MyClass extends SomeJsLib

  constructor: ->
    _super.apply @, arguments

Ответ 4

В моем исследовании javascript мне потребовался общий способ создания класса с динамическим числом аргументов конструктора. Как уже упоминалось, это не будет работать для массива, насколько я знаю, он будет работать только для классов стиля < script.

Вызов определенной функции с динамическим числом аргументов достаточно прост через .apply

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

f.apply measurement, args

Класс может расширять класс, сохраненный в переменной. В результате мы можем написать функцию, которая возвращает новые подклассы.

classfactory = (f) ->
    class extension extends f

Объединяя все это вместе, мы можем создать функцию, которая возвращает новые подклассы, в которых мы apply аргументы конструктору суперкласса.

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

Чтобы использовать этот новый factory

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

Мысли? Комментарии? Предложения? Ограничения, о которых я не думал? Дайте мне знать.