问题描述:

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!

网友答案:

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
网友答案:

$.extend takes the first object and adds to it the methods and variables defined in the second object. So:

var a = { foo: 1 };
var b = { bar: function () {} }
var c = $.extend(a, b);

Now:

c == a == { foo: 1, bar: function () {} )

In your original example, I suspect that:

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

is creating a closure so that this continues to refer to stuff, so that the stuff prototype gets extended.

In your second example, setFoo simply sets the value of a local variable, which is not carried forward when a new instance of stuff is created.

相关阅读:
Top