扩展类并将所有构造函数参数传递给super

10

如何使用CoffeeScript扩展一个类,同时将构造参数传递给super?

例如:

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

list = new List(1,2,3)

console.log list
[1, 2, 3]

把这个问题分成两个部分不是很好吗?第一个部分是关于将构造函数参数传递给超类的一般性问题,第二个部分则涉及到 Array 的奇怪行为。 - Mitja
4个回答

24

通常情况下,不需要额外的代码就可以工作;除非被明确覆盖,否则会使用父构造函数:

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

class B extends A

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

问题并不是 Array 没有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的构造函数,并且不带任何参数。


感谢您的出色解释!“我建议将List实现为一个围绕数组实例的包装器”。您会如何实现这个呢?如果您有时间,能否给出一个简短的示例? - Acorn
我只是想说构造函数看起来应该像@arr = Array::slice.call arguments, 0(将arguments方法转换为对象的标准方法),然后你需要将每个数组方法实现为简单的传递(例如: push: -> @arr.push.apply arr, arguments, toString: -> @arr.toString()等),最后添加自己的List方法。 - Trevor Burnham
哦,哇,逐个通过每个方法..听起来有点繁琐 :) - Acorn
1
或者,你可以这样写:@[method] = (=> method.apply @arr, arguments) for method of @arr - Trevor Burnham

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

    toString: ->
        @join('-')

list = new List(1, 2)

list.push(3)

list.toString()

=>

'1-2-3'

最好有一种通用的方式将所有参数传递给父对象的构造函数,但对于这种情况,这样做已经可以了 :) - Acorn
1
因为数组没有“构造函数”方法,所以不可能实现..但是,是的,这将是很好的。=) - jejacks0n
在严格模式下这是无效的,因为在该情况下"arguments"不存在。 - monokrome

2
使用 CoffeeScript 中的 extends 时,期望超类也是 CoffeeScript。如果您使用的是非 CoffeeScript 类,例如原始问题中的 Array,则可能会遇到问题。
对我来说,这解决了一般情况。这有点像黑客技巧,因为它使用了 _super,而这可能不是编译后的 JS 的预期用法。
class MyClass extends SomeJsLib

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

如果您只想将调用者的参数传递:

class MyClass extends SomeJsLib

  constructor: ->
    _super.apply @, arguments

-1
在我探索 JavaScript 的过程中,我需要一种通用的方式来创建一个具有动态数量构造函数参数的类。正如所提到的那样,据我所知,这对于数组是行不通的,它只适用于 CoffeeScript 风格的类。
通过 .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

使用这个新工厂

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

有什么想法?评论?建议?我没有考虑到的限制?请告诉我。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接