用于实例化扩展现有对象的 CoffeeScript class 实例的实用函数

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

所以我一直在研究 CoffeeScript 中的原型继承,特别是研究如何编写从特定对象而不是另一个 class 继承的 CoffeeScript classes类似于 Crockford 的对象函数。本质上,我想做的是编写一个 class ,它可以从传递给其构造函数的特定对象继承。不幸的是,我认为如果不求助于 setPrototypeOf,这可能是不可能的,考虑到关于它的相当惊人的警告,我宁愿不这样做。相反,我可能会选择一个可以做类似事情的函数。以下是两种可能性:

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

现在,我非常喜欢第二种方法,因为基本上它返回的是一个新的 class,然后您可以使用常规构造函数语法。只有一个问题:虽然使用 extendObject 创建的对象正确识别为 Examples,但使用 extendObjectMaker 返回的构造函数创建的对象识别为 Fs,并且不是 Fs 的实例Example.

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

鉴于这些函数使用几乎完全相同的代码,我很难弄清楚为什么它们表现出不同的行为。那么,有谁知道为什么 test2 没有显示为 Example,我需要更改什么才能让它显示出来?

查看 CoffeeScript 源代码:http://coffeescript.org/v1/annotated-source/nodes.html#section-60

CoffeeScript 以不同方式处理构造函数调用,具体取决于它们是使用 splat (args...) 调用还是不使用 splat 调用。

如果您 使用 new maker [2]... 调用 extendObjectMaker 重新编写您的函数,您的代码将给出所需的结果如下:

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