2

来自 C++/Java 背景,CoffeeScript 中的 OOP-Inheritance 让我感到困惑。

考虑以下示例:

class BaseClass
    arr: []

    addItem: (item) =>
        @arr.push item

class SubClassA extends BaseClass
    constructor: ->
        @addItem("fromSubA")

class SubClassB extends BaseClass


console.log "Case 1"
instB = new BaseClass()
instA = new SubClassA()
console.log "instA: #{JSON.stringify instA.arr}"
console.log "instB #{JSON.stringify instB.arr}"

console.log "Case 2"
instB = new SubClassB()
instA = new SubClassA()
console.log "instA: #{JSON.stringify instA.arr}"
console.log "instB #{JSON.stringify instB.arr}"

console.log "Case 3"
instB = new SubClassB()
instA = new SubClassA()
console.log "instA: #{JSON.stringify instA.arr}"
console.log "instB #{JSON.stringify instB.arr}"

tinkerbin.com 中的输出:

Case 1
instA: ["fromSubA"] 
instB ["fromSubA"] 

Case 2
instA: ["fromSubA","fromSubA"] 
instB ["fromSubA","fromSubA"] 

Case 3
instA: ["fromSubA","fromSubA","fromSubA","Added manually, only to instB"] 
instB ["fromSubA","fromSubA","fromSubA","Added manually, only to instB"] 

Iow:基类的“arr”实例属性的行为或多或少类似于静态属性;如果我在一个实例中更改数组,它在另一个实例中也会更改。为什么这个数组在实例之间共享?

令人困惑的是,字符串属性没有表现出这种行为:

class BaseClass
    property: "From Base"    

class SubClassA extends BaseClass
    constructor: ->
        @property = "fromSubClassA"

class SubClassB extends BaseClass


document.write "Case 1<br>"
instB = new BaseClass()
instA = new SubClassA()
document.write "#{instA.property} <br>"
document.write "#{instB.property} <br><br>"

document.write "Case 2<br>"
instB = new SubClassB()
instA = new SubClassA()
instA.property = "test"
document.write "#{instA.property} <br>"
document.write "#{instB.property} <br>"

这段代码工作得很好,保持实例之间的“属性”属性隔离。

我显然在这里误解了一些东西。是什么导致阵列在实例之间共享?

4

2 回答 2

2

看看生成的 JavaScript 是什么样子的:

var BaseClass,
  __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

BaseClass = (function() {
  function BaseClass() {
    this.addItem = __bind(this.addItem, this);
  }

  BaseClass.prototype.arr = [];

  return BaseClass;

})();

如您所见,arr是 的原型的属性,BaseClass就像 Python 等语言中的类变量一样。该数组只有一个实例存在并且在该类的所有实例之间共享,因此如果您修改它,它会在任何地方修改(通过访问instance.arr,您将遍历原型链直到同一个BaseClass.prototype.arr数组)。

字符串在 JavaScript 中是不可变的,因此在这方面它们的行为不像数组。

于 2013-06-12T15:29:02.967 回答
2

在您的示例arr中是一个类(即静态)属性变量,因此它与您的所有实例共享BaseClass

您需要在方法中编辑BaseClass并初始化arr属性constructor

class BaseClass
    constructor: ->
        @arr = []

    addItem: (item) =>
        @arr.push item

然后您要确保使用关键字SubClassA调用构造函数:BaseClasssuper()

class SubClassA extends BaseClass
    constructor: ->
        super()
        @addItem("fromSubA")
于 2013-06-12T15:57:39.583 回答