OOP Javascript - 隔离类中的对象

时间:2011-06-13 01:25:17

标签: javascript prototype-programming

我正在尝试创建一个主对象,我可以创建多个实例,每个实例都继承子项(具有唯一/隔离属性)。但是,当我这样做时,对象的属性(在被更改之后)正在改变所有创建的对象。我可能没有正确解释这个,但这个例子应该很清楚。

Main = function(){};

// Extending the main class with new object. Doing it this way so I can have these in
// separate files.
Main.prototype.foo = {
    bar: 1
}

// First instance of Main().
var A = new Main();

// Second instance of Main().
var B = new Main();

// Set the bar property to different values for each Main() object.
A.foo.bar = 2;
B.foo.bar = 3;

// Both A.foo.bar and B.foo.bar return 3.
alert(A.foo.bar);
alert(B.foo.bar);

我想要发生的事情是,A.foo.bar返回2而B.foo.bar返回3,这样我就有了彼此独立的孤立对象。

有什么想法吗?我只是错过了一些明显的东西吗?非常感谢!

3 个答案:

答案 0 :(得分:5)

“foo”属性位于原型对象上,并且只有其中一个属性。当您通过任何实例设置它时,您正在影响同一个共享属性。

您可以在构造函数中添加实例属性:

  function Main() {
    this.instanceProperty = 1;
  }

然后那将是每个实例。

原型不是“主模板”或类似的东西;这是一个真实的对象。它不会复制到实例上。相反,运行时知道它就在那里,并且当对实例上实际不存在的实例上的属性进行引用时,它就知道要走原型链并在那里寻找属性。

答案 1 :(得分:3)

其他答案或多或少是正确的,但他们缺少的是

之间存在差异
Main.prototype.foo = {
    bar: 1
};

Main.prototype.bar = 1;

在这两种情况下,实例化新的Main都会在其原型链中创建一个新实例,其属性为foobar。在这两种情况下,都可以重新定义实例级属性,而不会影响其他实例:

function Main() {};
Main.prototype.foo = {
    bar: 1
};
Main.prototype.bar = 1;

a = new Main();
b = new Main();

a.foo = { bar: 2 };
console.log(a.foo.bar, b.foo.bar); // 2 1

a.bar = 2;
console.log(a.bar, b.bar); // 2 1

但是当您实例化新的Main时,实例变量foo是对单个对象{bar:1}引用,它在所有实例之间共享。因此,当您设置a.foo.bar时,您正在更改公共对象,而不是实例变量;实例变量是引用a.foo

您不必在构造函数中初始化实例属性。标准方法是直接在原型上设置bar,即Main.prototype.bar = 1,这将为您提供初始化为1的独立实例变量。但是,如果您需要基于每个实例的更复杂的数据结构(对象,数组或另一个类的实例),那么您不能将其创建为原型上的属性,因为您将成为给每个实例一个对公共对象的引用 - 所以在构造函数中是要走的路:

function Main() {
    // instance-level object
    this.foo = {
        bar: 1
    };
}

答案 2 :(得分:1)

由于你在原型上编辑某些东西,它会影响每个对象。

但是,你可以这样做:

A.x = 2;
B.x = 3;

然后你会有不同的结果。

或者,你可以这样:

Main = function(val){
  this.x = val;
}

A = new Main(2);
B = new Main(3);