Proposal: Storage for getters and setters

Xavier MONTILLET xavierm02.net at gmail.com
Fri Sep 30 06:54:05 PDT 2011


My implementation sucks and doesn't keep per-instance values. Posting
revision soon.
http://jsfiddle.net/xavierm02/UzNK3/21/

On Fri, Sep 30, 2011 at 3:50 PM, Xavier MONTILLET
<xavierm02.net at gmail.com> wrote:
> Hi,
>
> I've been playing with getters and setters for a little while and
> there's one thing really bothering me: You can't store the value in
> the object in a hidden way. Here is an example:
>
> http://jsfiddle.net/xavierm02/UzNK3/13/
>
> function Point( x, y ) {
>    this.x = x;
>    this.y = y;
> }
> Object.defineProperties( Point.prototype, {
>    x: {
>        get: function ( ) {
>            // this would return the stored value
>        },
>        set: function ( value ) {
>             value = parseInt( value );
>            // and here, you would want to set "this.x" to value but
> you can't since this would create an infinite loop
>        }
>    },
>    y: {
>        // same here
>    }
> } );
>
> You could do it by:
>
> - using Object.defineProperties in the constructor and therefore but
> then, you would have several times the same function created so it
> kinda sucks.
>
> http://jsfiddle.net/xavierm02/UzNK3/14/
>
> function Point( x, y ) {
>    Object.defineProperties( Point.prototype, {
>        x: {
>            get: function ( ) {
>                return x;
>            },
>            set: function ( value ) {
>                x = parseInt( value, 10 );
>            }
>        },
>        y: {
>            // same here
>        }
>    } );
> }
>
> - have some kind of array where you store values and another array
> where you store the this and let those arrays be accessible only from
> the methods needing it. Then you would get the index of the instance
> by doing indexOf( this ) on the array of instances and then you would
> search for the value at this index. Sucks too.
>
> http://jsfiddle.net/xavierm02/UzNK3/15/
>
> ( function ( ) {
>    var instances = [ ],
>    xs = [ ],
>    ys = [ ];
>    function Point( x, y ) {
>        instances.push( this );
>        xs.push( x );
>        ys.push( y );
>    }
>    Object.defineProperties( Point.prototype, {
>        x: {
>            get: function ( ) {
>                return xs[ instances.indexOf( this ) ];
>            },
>            set: function ( value ) {
>                xs[ instances.indexOf( this ) ] = parseInt( value );
>            }
>        },
>        y: {
>            // same here
>        }
>    } );
>    this.Point = Point;
> } )( );
>
> I don't know know what you think of this but these methods really
> aren't convenient from my point of view...
>
> There are potential new features that could allow you to do this too:
>
> - private properties but then that would mean giving access to private
> properties to the methods in the prototype, which would mean that
> adding a method in the prototype would allow to change the values,
> which isn't what you want... Even though you could freeze the
> prototype to avoid it...
> - I remember thinking of another one but I can't remember which one atm...
>
> So here'swhat I propose:
> - the getter gets a parameter which is the stored value
> - the setter's return value is set as value for the "private" property
>
> Here's an implementation of what I would like having (It sucks sinces
> it prevents garbage collecting and could easilly be optimized but
> still works):
>
> http://jsfiddle.net/xavierm02/UzNK3/17/
>
> Object.defineProperties = ( function ( ) {
>    var defineProperties = Object.defineProperties;
>    return function ( object, propertyDescriptors ) {
>        for ( var name in propertyDescriptors ) {
>            if ( propertyDescriptors.hasOwnProperty( name ) ) {
>                ( function ( propertyDescriptor ) {
>                    var get;
>                    var set;
>                    if ( propertyDescriptor.hasOwnProperty( 'get' ) ) {
>                        get = propertyDescriptor.get;
>                        propertyDescriptor.get = function ( ) {
>                            return get.call( this, propertyDescriptor.value );
>                        };
>                    }
>                    if ( propertyDescriptor.hasOwnProperty( 'set' ) ) {
>                        set = propertyDescriptor.set;
>                        propertyDescriptor.set = function ( value ) {
>                            return propertyDescriptor.value =
> set.call( this, value );
>                        };
>                    }
>                } )( propertyDescriptors[ name ] );
>            }
>        }
>        defineProperties( object, propertyDescriptors );
>    };
> } )( );
>
> And you would use it that way:
>
> http://jsfiddle.net/xavierm02/UzNK3/17/
>
> function Point( x, y ) {
>    this.x = x;
>    this.y = y;
> }
> Object.defineProperties( Point.prototype, {
>    x: {
>        get: function ( value ) {
>            return value;
>        },
>        set: function ( value ) {
>            value = parseInt( value );
>            return value;
>        }
>    },
>    y: {
>        // same here
>    }
> } );
>
> Of course, if it were implemented, it would probably allow setting a
> defaut setter that woudl simply assign and a a default getter that
> would simply return the value by putting true instead of the function.
> Or somthing similar.
>
> Of course, for this example, implementing type checking would make it useless.
> But that really was just a example. Something where it would have a
> real use is, for example:
>
> http://jsfiddle.net/xavierm02/UzNK3/20/
>
> // isn't suposed to work
> // here just for wyntax coloration
> function WYSIWYGEditor( ) {
>    Object.defineProperties( this, {
>        iframe: {
>            value: document.createElement( 'iframe' ),
>            configurable: false,
>            enumerable: true,
>            writable: false
>        },
>        textarea: {
>            value: document.createElement( 'textarea' ),
>            configurable: false,
>            enumerable: true,
>            writable: false
>        },
>        container: {
>            value: document.createElement( 'div' ),
>            configurable: false,
>            enumerable: true,
>            writable: false
>        }
>    } );
>    Object.defineProperty( this, 'wysiwygField', {
>        value: this.iframe./* get the container */,
>        configurable: false,
>        enumerable: true,
>        writable: false
>    } )
>    this.container.appendChild( iframe );
> }
> Object.defineProperties( WYSIWYGEditor.prototype, {
>    wysiwyg: {
>        value: true,
>        configurable: false,
>        enumerable: true,
>        get: function ( value ) {// or simply true or somethign
> similar is shorcuts are implemented
>            return value
>        },
>        set: function ( value ) {
>            value = !!value;
>            if ( value ) {
>                this.wysiwygField.innerHTML = this.textarea.value;
>                this.container.removeChild( this.textarea );
>                this.container.appendChild( this.iframe );
>            } else {
>                this.textarea.value = this.wysiwygField.innerHTML;
>                this.container.removeChild( this.iframe );
>                this.container.appendChild( this.textarea );
>            }
>            return value;
>        }
>    }
> } );
>
> What do you think?
>


More information about the es-discuss mailing list