Javascript从构造函数扩展

时间:2014-02-17 07:19:57

标签: javascript prototypal-inheritance

让我说我有这个:

function Foo(){
   this.name = "fooos";
};

现在稍后在脚本中我引用了Foo,以及在实例化时向Foo添加属性的内容。我可以这样做:

Foo.prototype.myProp = 3;

foo = new Foo();

expect(foo).to.have.property('name');
expect(foo).to.have.property('myProp');

这很有用,直到我需要将一个对象附加到原型上,如下所示:

Foo.prototype.myProp = { bar : 3 };

问题是现在实例将在bar上共享状态(因为`bar只是一个参考):

foo = new Foo();
foo2 = new Foo();

foo.myProp.bar = 5;
expect(foo2.myProp.bar).to.equal(5);

哪个不可取。但是,如果在构造函数中添加了对象,则实例不会共享状态。

有解决方法吗?我无权访问构造函数来操作它。我需要将一个对象附加到原型中的实例。

2 个答案:

答案 0 :(得分:6)

属性不必在原型上,您只需将它们直接添加到实例:

var f = new Foo();
f.myProp = { bar: 3 };

  

我知道。这不是我想要的。

我能想到通过原型使用属性(不是方法; @meager使用方法a solution)来实现这一目标的唯一方法是丑陋的黑客攻击在原型上使用Object.defineProperty(仅限ES5)定义属性,然后在首次访问时重新定义,如下所示:

Object.defineProperty(Foo.prototype, "myProp", {
    get: function() {
        var obj = { bar: 3 };
        Object.defineProperty(this, "myProp", {
            get: function() {
                return obj;
            },
            set: function(value) {
                obj = value;
            }
        });
        return obj;
    }
});

Live Example | Source

我会 推荐。 : - )


另一种方法是在Foo前面放置一个外观,如下所示:

var OriginalFoo = Foo;
Foo = function() {
    OriginalFoo.apply(this, arguments);
    this.myProp = { bar: 3 };
};
Foo.prototype = Object.create(OriginalFoo.prototype);

当然,这只会在执行此代码后才适用于通过new Foo 创建的对象。

答案 1 :(得分:2)

根据您对需要完成原型的限制,您无法执行此操作。原型是共享的,你不能通过原型给每个实例一个唯一的对象。通过定义原型是非常不可能的。

最接近的是添加一个访问器方法,该方法将该属性延迟添加到特定实例,但这与您的问题相去甚远:

Foo.prototype.getMyProp = function () {
  this.myProp = this.myProp || { bar: 3; }
  return this.myProp
}

foo = new Foo();
foo2 = new Foo();

foo.getMyProp().bar = 5
expect(foo2.getMyProp().bar).to.equal(3);