I want to be able to learn creating Objects per the new JavaScript ECMA 5 standards, and use them in my current projects, without breaking functionality. But I see un-explainable stuff that makes me afraid
Consider the following code:
var foo = {
oldProp: 'ECMA Script 3',
newProp: 'ECMA Script 5'
};
// The new way of inheritance
var bar = Object.create( foo );
// and of assigning properties, if I am right
var bar2 = Object.create( Object.prototype, {
oldProp: { value: 'ECMA Script 3'},
newProp: { value: 'ECMA Script 5'}
});
// and then
bar;
// console output
Object {oldProp: "ECMA Script 3", newProp: "ECMA Script 5"}
// whereas !!
bar2;
Object {} // Why this?
Also,
bar.hasOwnProperty('oldProp'); // false, whereas
bar2.hasOwnProperty('oldProp'); // true !! It should be the other way round, right?
Additionally, I am not able to change the property of bar2
bar2.oldProp = "Marry had a little lamb";
bar2.oldProp; // "ECMA Script 3"
And more --
for (k in bar2) console.log(bar2[k]) // undefined
Am I creating the Objects in a correct way? What I basically want to achieve is getting rid of constructors.
Old code:
var Slideshow = function(type) {
this.type = type;
this.deleteSlideshow = function() {
// some code
}
}
Slideshow.prototype.nextSlide = function() {
// lotsa code
}
var vanityFairSlideshow = new Slideshow('wide-screen');
I want to change to Object.create
, may be kind of this:
var Slideshow = Object.create({ /* prototype */ }, { /* properties and methods */ });
var vanityFairSlideshow = Object.create( Slideshow , { /* properties and methods */ });
Whats the proper way of doing it?
That is because the second argument to
Object.create
resemblesObject.defineProperties
- and that means you are using property descriptors. While you are only setting the value, theenumerable
,writable
andconfigurable
flags default tofalse
.Either you explicitly set the
enumberable
andwritable
flags explicitly totrue
, or you don't use the second parameter:However, if this looks too lengthy to you, you would use a factory utility function - basically a constructor.
Your problem here is the defaults for the descriptors (aside from
value
) that you omitted for each property.Using this syntax (like for
defineProperty
anddefineProperties
),writable
isfalse
by default, andenumerable
isfalse
.Setting both of these to
true
will result in the behaviour you expect.http://jsfiddle.net/YZmbg/
Also, hopefully you appreciate how this isn't supported in all browsers; note the compatibility table for
Object.create
. Shims which adhere to thewritable
andconfigurable
properties do not, and cannot, exist.Finally, +1 for such a well written question; it's a breath of fresh air.
bar
is created without any property andfoo
as its prototype, sobar.hasOwnProperty('oldProp');
consequently returns false.For
bar2
you don't provide descriptors and the default value forenumerable
and writable isfalse
. So you can't change the properties or enumerate them in afor...in
loop.As for Am I creating the Objects in a correct way?: What you are doing is reasonable. You create
Slideshow
as a prototype for all slideshows and create a slideshow with this prototype and additional properties.I will try to answer on this question:
First small example. Imagine that we have this simple structure:
Now we want
AdvancedSlideshow
to inherit fromSlideshow
. So we want all functions from parent available for instances of its child. WithoutObject.create
we did it like that:Now
AdvancedSlideshow
inherits everything fromSlideshow
, but alsoSlideshow
inherits everything fromAdvancedSlideshow
. That is what we dont want.So we have to use something more complicated. There is a polyfill made by Douglas Crockford a long time ago.
Well first it wasnt polyfill, it was small pattern and it looked like otherwise. But pattern was evolving and then it was so good that it became part of javascript. So now we have just a polyfill for browsers that doesnt support ecmascript-5. And we can code:
instead of
Then
AdvancedSlideshow
inherits fromSlideshow
butSlideshow
doesnt inherit fromAdvancedSlideshow
.So purpose of
Object.create
isnt to get rid of constructors or "new" keywords. Its purpose is to make correct prototype chain!EDIT 20.2.2014: Few days ago I reallized, that
constructor
property is part of the prototype chain. So if we useObject.create
for inheritance, we also changeconstructor
property (not the constructor itself, just a property) of our child object. Therefore constructor property of new instance of child object points its parent. We can fix that with simpleChild.prototype.constructor = Child
.Now, there is a second parametr for Object.create which allows you to make lets say "hidden secrets" of objects. But I dont recommend you to do this, because you dont need it. It is something advanced that also works like some patterns.
If you want to avoid constructor, "new" keyword or anything important, then you are probably looking for some factory pattern. But remember, for example "new" has some weaknesses but pattern for removing built-in features are usually worse! Anyway, maybe you can find some inspiration here:
http://www.2ality.com/2010/12/javascripts-prototypal-inheritance.html