Methods can now be properly overridden when visibility is escalated
parent
170eb06af6
commit
61f2f7e22d
|
@ -61,7 +61,12 @@ exports.setup = function( dest, properties, methods )
|
||||||
// initialize each of the properties for this instance to
|
// initialize each of the properties for this instance to
|
||||||
// ensure we're not sharing references to prototype values
|
// ensure we're not sharing references to prototype values
|
||||||
doSetup( dest, properties[ 'public' ] );
|
doSetup( dest, properties[ 'public' ] );
|
||||||
doSetup( dest, properties[ 'protected' ], methods[ 'protected'] );
|
|
||||||
|
// Do the same for protected, but only if they do not exist already in
|
||||||
|
// public. The reason for this is because the property object is laid /atop/
|
||||||
|
// of the public members, meaning that a parent's protected members will
|
||||||
|
// take precedence over a subtype's overriding /public/ members. Uh oh.
|
||||||
|
doSetup( dest, properties[ 'protected' ], methods[ 'protected' ], true );
|
||||||
|
|
||||||
// then add the private parts
|
// then add the private parts
|
||||||
doSetup( obj, properties[ 'private' ], methods[ 'private' ] );
|
doSetup( obj, properties[ 'private' ], methods[ 'private' ] );
|
||||||
|
@ -79,7 +84,7 @@ exports.setup = function( dest, properties, methods )
|
||||||
*
|
*
|
||||||
* @return {undefined}
|
* @return {undefined}
|
||||||
*/
|
*/
|
||||||
function doSetup( dest, properties, methods )
|
function doSetup( dest, properties, methods, unless_exists )
|
||||||
{
|
{
|
||||||
var hasOwn = Array.prototype.hasOwnProperty;
|
var hasOwn = Array.prototype.hasOwnProperty;
|
||||||
|
|
||||||
|
@ -89,11 +94,20 @@ function doSetup( dest, properties, methods )
|
||||||
for ( method_name in methods )
|
for ( method_name in methods )
|
||||||
{
|
{
|
||||||
if ( hasOwn.call( methods, method_name ) )
|
if ( hasOwn.call( methods, method_name ) )
|
||||||
|
{
|
||||||
|
// If requested, do not copy the method over if it already
|
||||||
|
// exists in the destination object. Don't use hasOwn here;
|
||||||
|
// unnecessary overhead and we want to traverse any prototype
|
||||||
|
// chains. We do not check the public object directly, for
|
||||||
|
// example, because we need a solution that will work if a proxy
|
||||||
|
// is unsupported by the engine.
|
||||||
|
if ( !unless_exists || ( dest[ method_name ] === undefined ) )
|
||||||
{
|
{
|
||||||
dest[ method_name ] = methods[ method_name ];
|
dest[ method_name ] = methods[ method_name ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// initialize private/protected properties and store in instance data
|
// initialize private/protected properties and store in instance data
|
||||||
for ( prop in properties )
|
for ( prop in properties )
|
||||||
|
|
|
@ -657,3 +657,38 @@ var common = require( './common' ),
|
||||||
}, Error, "Cannot de-escalate visibility for interface members" );
|
}, Error, "Cannot de-escalate visibility for interface members" );
|
||||||
} )();
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Due to the way the property object is laid atop of the public members, we
|
||||||
|
* need to ensure that protected methods' functionality can /actually/ be
|
||||||
|
* overridden, since the protected method is higher in the prototype chain and
|
||||||
|
* therefore will be accessed before the public method.
|
||||||
|
*
|
||||||
|
* We don't care about private -> protected, because that's not possible through
|
||||||
|
* inheritance.
|
||||||
|
*/
|
||||||
|
( function testCanOverrideProtectedMethodFunctionalityWithPublic()
|
||||||
|
{
|
||||||
|
// get the result of invoking overridden foo()
|
||||||
|
var result = Class(
|
||||||
|
{
|
||||||
|
'protected foo': function()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
} ).extend(
|
||||||
|
{
|
||||||
|
// override and escalate visibility of method foo()
|
||||||
|
'public foo': function()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
} )().foo();
|
||||||
|
|
||||||
|
// if the override was successful, we'll be able to invoke the overridden
|
||||||
|
// method
|
||||||
|
assert.equal( result, true,
|
||||||
|
"Can properly override protected methods with public"
|
||||||
|
);
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue