coope/lst/ctor-factory-priv.js

124 lines
2.4 KiB
JavaScript

var Class = ( function( extending )
{
// implementation left to reader
var _privname = getRandomName();
var C = function( dfn )
{
// extend from an empty base
return C.extend( null, dfn );
};
C.extend = function( base, dfn )
{
base = base || function() {};
// prevent ctor invocation
extending = true;
var ctor = function()
{
// do nothing if extending
if ( extending )
{
return;
}
// call "actual" constructor
this.__construct &&
this.__construct.apply(
this, arguments
);
};
// public prototype
ctor.prototype = new base();
ctor.prototype.constructor = ctor;
// private prototype (read-only,
// non-configurable, non-enumerable)
Object.defineProperty(
ctor, _privname, { value: {} }
);
copyTo(
ctor.prototype,
ctor[ _privname ],
dfn
);
// done extending; clear flag to
// ensure ctor can be invoked
extending = false;
return ctor;
};
function copyTo( pub, priv, members )
{
var hasOwn = Object.prototype
.hasOwnProperty;
for ( var member in members )
{
if ( !hasOwn.call( members, member ) )
{
continue;
}
// if prefixed with an underscore,
// assign to private "prototype"
var dest = ( member[ 0 ] === '_' )
? priv : pub;
dest[ member ] = wrap(
members[ member ]
);
}
}
function wrap( method )
{
return function()
{
this.__priv =
this.constructor[ _privname ];
var retval = method.apply(
this, arguments
);
this.__priv = undefined;
return retval;
};
}
return C;
} )( false );
// dummy implementation
function getRandomName()
{
return '__privobj';
}
var Foo = Class(
{
getValue: function()
{
return this.__priv._getPrivValue();
},
_getPrivValue: function()
{
return 'private';
}
} );
var inst = new Foo();
inst.getValue(); // "private"
inst._getPrivValue(); // TypeError
inst.__priv; // undefined