Как бы вы расширили класс, используя CoffeeScript, но аргументы конструкции переданы супер?
Например:
class List extends Array
# Some other stuff to make it work...
list = new List(1,2,3)
console.log list
[1, 2, 3]
Как бы вы расширили класс, используя CoffeeScript, но аргументы конструкции переданы супер?
Например:
class List extends Array
# Some other stuff to make it work...
list = new List(1,2,3)
console.log list
[1, 2, 3]
class List extends Array
constructor: ->
@push arguments...
toString: ->
@join('-')
list = new List(1, 2)
list.push(3)
list.toString()
= >
'1-2-3'
В общем, это будет работать без дополнительного кода; родительский конструктор используется, если явно не переопределяется:
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
без аргументов.
Использование extends
в CoffeeScript ожидает, что суперкласс также будет в CoffeeScript. Если вы используете не-CS-класс, например. Array
в исходном вопросе, тогда вы можете столкнуться с проблемами.
Это разрешило мне общий случай. Это немного хак, потому что он использует _super
, который, вероятно, не предназначен для использования в скомпилированном JS.
class MyClass extends SomeJsLib
constructor: ->
_super.call @, arg1, arg2
Или если вы просто хотите передать аргументы от вызывающего:
class MyClass extends SomeJsLib
constructor: ->
_super.apply @, arguments
В моем исследовании 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)
Мысли? Комментарии? Предложения? Ограничения, о которых я не думал? Дайте мне знать.