124 lines
2.4 KiB
JavaScript
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
|