Fix setting public properties
- This currently only works with ES5 engines - Fallback to follow so this will work with pre-ES5 engines - As such, I do not recommend using this commit outside of ES5-compliant engines that work properly with getters/setters - This does NOT include IE8, as IE8 only works with getters/setters on DOM elementsclosure/master
parent
74c2fc57c1
commit
bc9e2bb7b2
19
lib/class.js
19
lib/class.js
|
@ -537,6 +537,25 @@ function attachPropInit( prototype, properties, members )
|
|||
// initialize the value with a clone to ensure that they do
|
||||
// not share references (and therefore, data)
|
||||
this[ prop ] = util.clone( prop_pub[ prop ] );
|
||||
|
||||
( function( prop )
|
||||
{
|
||||
var inst = this;
|
||||
|
||||
// public properties, when set internally, must forward to the
|
||||
// actual variable
|
||||
inst_props.__defineSetter__( prop, function( val )
|
||||
{
|
||||
inst[ prop ] = val;
|
||||
} );
|
||||
|
||||
// since we're defining a setter, we'll need to define a getter
|
||||
// to return the value, or we'll simply return undefined
|
||||
inst_props.__defineGetter__( prop, function()
|
||||
{
|
||||
return inst[ prop ];
|
||||
} );
|
||||
} ).call( this, prop );
|
||||
}
|
||||
|
||||
var methods_protected = members[ 'protected' ],
|
||||
|
|
|
@ -50,9 +50,22 @@ var common = require( './common' ),
|
|||
// protected/private properties (for testing purposes)
|
||||
return this[ name ];
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Allows us to set a value from within the class
|
||||
*/
|
||||
'public setValue': function( name, value )
|
||||
{
|
||||
this[ name ] = value;
|
||||
},
|
||||
})();
|
||||
|
||||
|
||||
/**
|
||||
* Public members are the only members added to the instance's prototype to be
|
||||
* accessible externally
|
||||
*/
|
||||
( function testPublicMembersAreAccessbileExternally()
|
||||
{
|
||||
assert.equal(
|
||||
|
@ -69,6 +82,67 @@ var common = require( './common' ),
|
|||
} )();
|
||||
|
||||
|
||||
/**
|
||||
* For reasons that are discussed in the next test (writing to public
|
||||
* properties), we need to make sure public members are available internally.
|
||||
* Actually, we don't need to test public methods, really, but it's in there for
|
||||
* good measure. Who knows what bugs may be introduced in the future.
|
||||
*
|
||||
* This ensures that the getter is properly proxying the value to us.
|
||||
*/
|
||||
( function testPublicMembersAreAccessibleInternally()
|
||||
{
|
||||
assert.equal(
|
||||
foo.getProp( 'pub' ),
|
||||
pub,
|
||||
"Public properties are accessible internally"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
foo.getProp( 'pubf' )(),
|
||||
pub,
|
||||
"Public methods are accessible internally"
|
||||
);
|
||||
} )();
|
||||
|
||||
|
||||
/**
|
||||
* This may sound like an odd test, but it's actually very important. Due to how
|
||||
* private/protected members are implemented, it compromises public members. In
|
||||
* fact, public members would not work internally without what is essentially a
|
||||
* proxy via setters.
|
||||
*
|
||||
* This test is to ensure that the setter is properly forwarding writes to the
|
||||
* object within the prototype chain containing the public values. Otherwise,
|
||||
* setting the value would simply mask it in the prototype chain. The value
|
||||
* would appear to have changed internally, but when accessed externally, the
|
||||
* value would still be the same. That would obviously be a problem ;)
|
||||
*/
|
||||
( function testPublicPropertiesAreWritableInternally()
|
||||
{
|
||||
var val = 'moomookittypoo';
|
||||
|
||||
// start by setting the value
|
||||
foo.setValue( 'pub', val );
|
||||
|
||||
// we should see that change internally...
|
||||
assert.equal(
|
||||
foo.getProp( 'pub' ),
|
||||
val,
|
||||
"Setting the value of a public property internally should be " +
|
||||
"observable /internally/"
|
||||
);
|
||||
|
||||
// ...as well as externally
|
||||
assert.equal(
|
||||
foo.pub,
|
||||
val,
|
||||
"Setting the value of a public property internally should be " +
|
||||
"observable /externally/"
|
||||
);
|
||||
} )();
|
||||
|
||||
|
||||
( function testProtectedAndPrivateMembersAreNotAccessibleExternally()
|
||||
{
|
||||
assert.equal(
|
||||
|
|
Loading…
Reference in New Issue