Proposal: Storage for getters and setters
Xavier MONTILLET
xavierm02.net at gmail.com
Fri Sep 30 06:50:56 PDT 2011
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