2

Lets say I have this:

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

Now later in the script I have a reference to Foo, and what to add properties to Foo when instantiated. I could do something like this:

Foo.prototype.myProp = 3;

foo = new Foo();

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

This works great until I need to attach an object to prototype, like so:

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

The issue is that now instances will share state on bar (as `bar is just a reference):

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

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

Which is not desirable. However if the object is added inside the constructor the instances do not share state.

Is there a way around this? I don't have access to the constructor to manipulate it. I need to attach an object to an instance from the prototype.

0

2 Answers 2

6

Properties don't have to be on prototypes, you can just add them directly to instances:

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

I know that. Its not what I want.

The only way I can think of to do this via the prototype with a property (not a method; @meager has a solution using a method) is an ugly hack where you define the property on the prototype with Object.defineProperty (ES5-only) and then redefine it on first access, like this:

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

I would not recommend that. :-)


An alternative would be to throw a facade in front of Foo, like this:

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

That would, of course, only apply to objects created via new Foo after this code executed.

Sign up to request clarification or add additional context in comments.

7 Comments

I know that. Its not what I want.
In what way is this not what you want? From your question it seems to me this is exactly what you want.
If the script makes another instance of Foo later on it won't have myProp attached. I want to it be a part of the constructor.
@Fresheyeball: I've added an ugly hack way of doing it, but the nature of the question suggests that you really want to derive from Foo (possibly throwing a facade over it), rather than this. I've also added a note about that.
I get it. This is just an experiment. defineProperty version turns out to be right on the money
|
2

You cannot do this based on your restriction of needing to go through the prototype. The prototype is shared, you cannot give each instance a unique object through the prototype. It's pretty much impossible by definition of what the prototype is.

The closest thing would be to add an accessor method which lazily adds the property to the specific instance, but this is pretty far removed from your ask:

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);

1 Comment

Could work, if using a method is acceptable for the OP.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.