理解Coffee Script中的类扩展和实例属性

时间:2013-04-09 03:10:39

标签: javascript oop coffeescript

我刚刚进入Coffee Script并且在解决课程扩展如何运作方面遇到了问题。在扩展该类时,似乎将父类定义为实例属性的属性实现为静态属性。

我有一个名为Foo的类,我想将它用作两个子类Bar和Goo的基类。我给Foo一个名为foobs的实例属性和一个添加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”属性,但出于某种原因,似乎即使foob是Foo上的一个实例属性,它也会被分配为Bar和Goo上的类属性。关于如何解决这个问题的任何想法?或者可能有不同的语法我不知道?

由于

3 个答案:

答案 0 :(得分: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数组。

答案 1 :(得分: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

这使得从未创建新数组更加清晰。

答案 2 :(得分:1)

foobs数组应该在构造函数中初始化,因为现在所有实例都会共享相同的foobs数组,因为您在prototype上定义了它。

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