Home & blog  /  2012  /  Feb  /  view post  /

ECMAScript 5: a revolution in object properties

posted: 29 Feb '12 20:03 tags: JavaScript, ECMA5, object

Over the coming weeks I'm going to focus on discussing the mini revolution that ECMAScript 5 brought, and the implications in particular for objects and their properties.

ECMA5's final draft was published at the end of 2009, but it was only really when IE9 launched in early 2011 - and, with it, impressive compatibility for ECMA5 - that it became a genuinely usable prospect. Now in 2012, it is being used more and more as browser vendors support it and its power becomes apparent. (Full ECMA5 compatibility table).

JavaScript has always been a bit of an untyped, unruly free-for-all. ECMAScript 5 remedies that somewhat by giving you much greater control over what, if anything, can happen to object properties once changed - and it's this I'll be looking at in this first post.

A new approach to object properties

In fact the whole idea of an object property has changed; it's no longer a case of it simply being a name-value pairing - you can now dictate all sorts of configuration and behaviour for the property. The new configurations available to each property are:

  • value - the property's value (obviously)
  • writable - whether the property can be overwritten
  • configurable - whether the property can be deleted or have its configuration properties changed
  • enumerable - whether it will show up in a for-in loop
  • get - a function to fire when the property's value is read
  • set - a function to fire when the property's value is set

Collectively, these new configuration properties are called a property's descriptor. What's vital to understand, though, is that some are incompatible with others.

Two flavours of objects

The extensive MDN article on ECMAScript 5 properties suggests thinking of object properties in two flavours:

  • data descriptors - a property that has a value. In its descriptor you can set value and writable but NOT get or set
  • accessor descriptors - a property described not by a value but by a pair of getter-setter functions. In its descriptor you can set get and set but NOT value or writable.

    Note that enumerable and configurable are usable on both types of property. I'm struggling to understand why someone thought the ability to set a value and a setter function, for example, were incompatible desires. If I find out, I'll let you know.

    New methods

    To harness this new power, you need to define properties in one of three ways - all stored as new static methods of the base Object object:

    • defineProperty()
    • defineProperties()
    • create()

    The first two work identically except the latter allows you to set multiple properties in one go. As for Object.create(), I'll be covering that separately in a forthcoming post.

    Object.defineProperty() is arguably the most important part of this new ECMAScript spec; as John Resig points out in his post on the new features, practically every other new feature relies on this methd.

    Object.defineProperty() accepts three arguments:

    • the object you wish to add a property to
    • the name of the property you wish to add
    • a descriptor object to configure the property (see descriptor properties above)

    Let's see it in action.

    1var obj1 = {};

    2Object.defineProperty(obj1, 'newProp', {value: 'new value', writable: false});

    3obj1.newProp = 'changed value';

    4console.log(obj1.newProp); //new value - no overwritten

    See how the overwrite failed? No error or warning is thrown - it simply fails silently. In ECMA5's new 'strict mode', though, it does throw an exception. (Thanks to Michiel van Eerd for pointing this out.)

    There we set a data descriptor. Let's set an accessor descriptor instead.

    1var obj = {}, newPropVal;

    2Object.defineProperty(obj, 'newProp', {

    3     get: function() { return newPropVal; },

    4     set: function(newVal) { newPropVal = newVal; }

    5});

    6obj.newProp = 'new val';

    7console.log(obj.newProp); //new val

    You might be wondering what on earth is going on with that newPropVal variable. I'll come to that in my next post which will look at getters and setters in detail. Note also how, with our setter, the new value is forwarded to it as its only argument, as you'd expect.

    The fact that these properties can be set only via these methods means you cannot create them by hand or in JSON files. So you can't do:

    1var obj = {prop: {value: 'some val', writable: false}}; //etc

    2obj.prop = 'overwritten'; //works; it's not write-protected

    ECMA 5 properties don't replace old-style ones

    An important thing to understand early on is that this new form of 'uber' property is not the default. If you define properties in the old way, they will behave like before.

    1var obj = {prop: 'val'};

    2obj.prop = 'new val'; //overwritte - no problemo

    Reporting back

    Note that these new configuration properties are, once set, not available via the API; rather, they are remembered in the ECMAScript engine itself. So you can't do this (using the example above):

    console.log(obj1.newProp.writable); //error; newProp is not an object

    Instead, you'll be needing Object.getOwnPropertyDescriptor. This takes two arguments - the object in question and the property you want to know about. It returns the same descriptor object you set above, so something like:

    {value: 'new value', writable: true, configurable: true, enumerable: true}

    More to come..

    So there you go - a very exciting mini revolution, as I said. This new breed of intelligent object property really is at the heart of arguably the most major shake-up to the language for a long time. Next week I'll continue this theme - stay posted!

    post new comment

    Comments (10)

    WebManWalking, at 2/03/'12 23:30, said:
    Did someone in ECMA forget deleters? If you delete an HTML5 dataset property, it's supposed to delete the associated data-* attribute. A way that a browser vendor could more easily implement that would be if the accessor routines include deleters. Better to standardize something up front if you realize in advance that the browser vendors are going to have to implement it anyway. 
    Adam, at 5/03/'12 20:40, said:
    : I agree; this does seem like something of a not-entirely-thought-out implementation. There are some quirks with it - the lack of deleters being one. Still, it's exciting the JS is heading towards a system of protected and trackable data in this way.
    Adam Eivy, at 9/03/'12 17:23, said:
    This sounds really cool. When you discuss creating the accessor descriptor, aren't you creating a global variable with newPropVal? I'm guessing that's a typo and not some odd new EMCA scope change :)
    
    Can't wait for the rest.
    Adam Eivy, at 9/03/'12 17:30, said:
    Oh, nevermind, I see it now. It's in the context of the object, so you are creating a new property called newPropVal. Dig it.
    Mitya, at 9/03/'12 17:42, said:
     Eviy: Thanks. Re: newPropVal, this is really weird. What gets me is that no where do you actually associate that with the value of the new property. The association seemingly comes only from the fact that both the getter and the setter reference it - i.e. the same variable. Before calling Object.defineProperty() I should have prepped the variable (i.e. var newPropval;) in order to avoid creating a global.
    Alex, at 12/03/'12 16:22, said:
    I kind of wish this had been baked into the object literal sytax as well. Something like,
    
    var obj = { get foo: function () {...}, set foo: function ( newValue ) {...}, enumerate foo: false, configure foo: false }
    
    Still a very nice feature to have, though.
    Michiel van Eerd, at 12/03/'12 18:11, said:
    Nice intro.
    
    "See how the overwrite failed? No error or warning is thrown - it simply fails silently; it's questionable whether that's ideal." If you are in strict mode ("use strict";), an exception will be raised.
    Mitya, at 12/03/'12 19:47, said:
     - this is very true. I've updated the post to reflect this. Thanks.
    a-sk, at 17/03/'12 11:39, said:
    Thank for the article.
    I believe you misspelt 'enumerable' by 'enumarable' in configuration properties list.
    Mitya, at 17/03/'12 11:48, said:
    @a-sk - how true - now corrected. Thanks.
    post new comment