我刚刚进入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上的类属性。关于如何解决这个问题的任何想法?或者可能有不同的语法我不知道?
由于
答案 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
中存储对象,除非您希望在所有实例之间共享这些值。