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

Making sense of class extension and instance properties in Coffee Script

本文关键字:扩展 实例 属性 Coffee Script      更新时间:2023-09-26

我刚刚进入咖啡脚本和我有问题弄清楚如何类扩展的工作原理。似乎在父类上定义为实例属性的属性在扩展该类时被实现为静态属性。

我有一个叫做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()

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

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

显然我在这里做错了什么。我想barInstance和gooInstance各自有自己的"foobs"属性,但出于某种原因,似乎即使foobs是Foo上的实例属性,它被分配为Bar和Goo上的类属性。有什么办法解决这个问题吗?或者可能有我不知道的不同语法?

谢谢

问题在于您如何声明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的每个实例

这是因为您将数组放置在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

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

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