为什么PrototypeJS类实例共享相同的属性?

时间:2016-02-22 18:57:18

标签: javascript prototypejs

我无法理解PrototypeJS多类实例。

这是我的代码示例:

var Test = Class.create();

Test.prototype = {
  settings: {
    a: {},
    b: {},
  },
  initialize: function(options) {
    this.settings.c = options.c;
  }
};

var a = new Test({c: 1});
console.log(a.settings);

var b = new Test({c: 2});
console.log(a.settings);

var c = new Test({c: 3});
console.log(a.settings);
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.min.js"></script>

预期结果: a.settings应包含值为“1”的“c”项。

实际结果: a.settings“c”等于“3”。

Screenshot from dev. tools

(注意,您需要在开发工具中展开对象才能看到它。)

为什么呢?我错过了什么,或者它是某种PrototypeJS错误?创建隔离类实例的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

每个实例共享相同的this.settings对象。必须在构造函数中初始化可变数据结构,而不是在原型上:

Test.prototype = {
  initialize: function(options) {
    this.settings =  {
      a: {},
      b: {},
      c: options.c;
    };
  }
};

请注意,这似乎是“传统方式”(根据文档),更新的方式是:

var Test = Class.create({
  initialize: function(options) {
    this.settings =  {
      a: {},
      b: {},
      c: options.c;
    };
  }
});

PrototypeJS documentation

实际上解决了这个问题
  

编程语言中的继承类型

     

通常我们区分基于类和原型的继承,后者特定于JavaScript。

     

原型继承当然是该语言非常有用的功能,但在实际创建对象时通常很冗长。这就是我们通过内部原型继承模拟基于类的继承(如在Ruby语言中)的原因。这有一定的影响。

     

[...]

     

我们可以尝试在Prototype中做同样的事情:

var Logger = Class.create({
  initialize: function() { },
  log: [],
  write: function(message) {
    this.log.push(message);
  }
});

var logger = new Logger;
logger.log; // -> []
logger.write('foo');
logger.write('bar');
logger.log; // -> ['foo', 'bar']
     

有效。但是,如果我们创建另一个Logger实例呢?

var logger2 = new Logger;
logger2.log; // -> ['foo', 'bar']

// ... hey, the log should have been empty!
     

您可以看到,虽然您可能期望新实例中有一个空数组,但它与前一个logger实例具有相同的数组。实际上,所有记录器对象都将共享同一个数组对象,因为它是通过引用而不是按值复制的。

     

而是使用默认值初始化您的实例:

var Logger = Class.create({
  initialize: function() {
    // this is the right way to do it:
    this.log = [];
  },
  write: function(message) {
    this.log.push(message);
  }
});