0

A bit of confusion regarding what exactly is going on here.

given this simple code :

stuff = (function(){
    function extendFoo(bar)
    {
        $.extend(this.foo,bar);
    }
    this.foo = {};

    return { foo : foo, extendFoo: extendFoo};
})();

Following this simple operation :

zz = Object.create(stuff);
zz.extendFoo({bar:'bar'});
vv = Object.create(stuff); //foo is still extended(??)

So from what I realized, operations conducted on the returned object form Object.create still affect the prototype of that Object, So when you create a new object, his prototype is changed, thus resulting in a 'modified' version.

This seems wrong on a lot of levels, Can anyone explain what's going on here?

this behavior is not reproducible using the following pattern :

stuff = (function(){

    function setFoo(bar)
    {
        this.foo = bar;
    }
    var foo;

    return { foo : foo, setFoo: setFoo};

})();

So I suspect $.extend is to blame here.

Any input would be great!

Patrick
  • 3,289
  • 2
  • 18
  • 31
  • Notice that `this.foo = {};` in that IEFE creates a global variable that you don't want, use `var foo = {}`. Doesn't make a difference for your problem though. – Bergi Mar 01 '15 at 23:05
  • Does [Prototypal inheritance - Issues with nested objects](http://stackoverflow.com/q/10131052/1048572) answer your questions sufficiently? That you use a module pattern and setter methods might obscure the problem – Bergi Mar 01 '15 at 23:06
  • You have two major errors in your code: the `foo` in `return { foo: foo,` is undefined, and the `this` in `this.foo = {}` is actually the `window` object. Please correct these – I-Lin Kuo Mar 02 '15 at 01:58

1 Answers1

1

This problem has nothing to do with the module pattern and everything to do with prototypes.

zz = Object.create(stuff) 

creates a new object with stuff as its prototype.

vv = Object.create(stuff) 

creates a new object with the same stuff object as its prototype.

Both zz and vv share the same prototype object, so if you modify the prototype object stuff, then changes will reflect in both derived objects zz and vv. It doesn't matter whether you're modifying the prototype via $.extend or other means, and it doesn't matter whether you're modifying the prototype via your derived object or your prototype.

In your code, the foo object is attached to the prototype, not to the derived objects zz and vv. When extendFoo is invoked on the derived object zz, it is modifying foo on the prototype, so changes to foo are shared by the derived objects.

In your second example, in setFoo

this.foo = bar;

what's happening is that you're setting the foo property on the derived object so now it overrides the prototype's foo. After you run setFoo on a derived object, that object's foo is no longer the prototype's foo. You can see this by running

zz = Object.create(stuff);
console.log(zz.hasOwnProperty('foo')); // false
zz.setFoo(bar);
console.log(zz.hasOwnProperty('foo')); // true
delete zz.foo;
console.print(zz.foo); // foo is the original foo, not null
console.log(zz.hasOwnProperty('foo')); // false

you'd actually get back your original foo instead of null.

The reason why setFoo works in the second case is because you are no longer modifying the prototype, so the changes are no longer shared between derived objects. With the original's

$.extend(this.foo,bar);

you're modifying the object this.foo in place and not overriding. You can also see this via hasOwnProperty

zz = Object.create(stuff);
console.log(zz.hasOwnProperty('foo')); // false
zz.extendFoo({bar:'bar'});
console.log(zz.hasOwnProperty('foo')); // false
I-Lin Kuo
  • 3,220
  • 2
  • 18
  • 25