2

我刚刚进入 Coffee Script 并且在弄清楚类扩展的工作方式时遇到了问题。似乎在父类上定义为实例属性的属性在扩展该类时被实现为静态属性。

我有一个名为 Foo 的类,我想将其用作两个子类 Bar 和 Goo 的基类。我给 Foo 一个名为 foob 的实例属性和一个添加 foob 的方法,如下所示:

class Foo
    foobs:[]
    addFoob: (foob) ->
        @foobs.push(foob)

我用 Bar 和 Goo 扩展 Foo,并创建新实例,如下所示:

class Bar extends Foo
    otherMethod: ->
        alert 'doing other stuff'

class Goo extends Foo
    secondMethod: ->
        alert 'doing second stuff'

barInstance = new Bar()
gooInstance = new Goo()

但是当我向 barInstance 添加一个 Foob 时,它也会被添加到 gooInstance!

barInstance.addFoob('test')

console.log gooInstance.foobs (outputs ["test"])

显然我在这里做错了什么。我希望 barInstance 和 gooInstance 都有自己的“foobs”属性,但由于某种原因,似乎即使 foobs 是 Foo 上的实例属性,它也被分配为 Bar 和 Goo 上的类属性。关于如何解决这个问题的任何想法?还是我不知道有不同的语法?

谢谢

4

3 回答 3

3

问题在于你如何声明foobs——你真的希望它在实例上,所以它应该在一个constructor函数中声明。目前它是在prototype所有实例共享的哪个上声明的。如果我们看看你的Foo声明编译成什么,我们可以看到是这样的:

class Foo
  foobs:[]
  addFoob: (foob) ->
    @foobs.push(foob)

编译为:

var Foo = (function() {
  function Foo() {}
  Foo.prototype.foobs = [];
  Foo.prototype.addFoob = function(foob) {
    return this.foobs.push(foob);
  };
  return Foo;
})();

你想要做的是声明一个这样的构造函数:

class Foo
  constructor: (@foobs = [])->     
  addFoob: (foob) ->
    @foobs.push(foob)

这将为. 的foobs每个实例添加一个数组Foo

于 2013-04-09T03:20:27.480 回答
2

这是因为您将数组放置到Foo原型上,因此它将在所有实例中共享。相反,您需要为每个实例创建一个数组Foo并直接添加它。

class Foo
  foobs:null, # This isn't needed, but it's good for documentation.
  constructor: ->
    @foobs = []
  addFoob: (foob) ->
    @foobs.push(foob)

换个角度看,你所拥有的基本上是:

sharedFoobs = []

class Foo
  foobs: sharedFoobs

这使得永远不会创建新数组更加清楚。

于 2013-04-09T03:18:38.990 回答
1

foobs数组应该在构造函数中初始化,因为现在所有实例都将共享同一个foobs数组,因为您在prototype.

您可以安全地在 上定义原始值,prototype因为这些值是不可变的,但是您应该避免将对象存储在 中prototype,除非您希望在所有实例之间共享这些对象。

于 2013-04-09T03:17:57.883 回答