Lasse said:
Since the only difference visible inside f will be the value of the
"this" operator, this will have to be sufficient. It cannot be
completely safe, but unless someone is deliberatly trying to cheat, it
should be fairly safe. Javascript has no language based protection
against malicious code.
You could try checking whether the value of "this" could be a new
object created with "new f()". E.g., check
this.constructor == f
or
this instanceof f
Oh thanks, I finally settled on:
function f()
{
if( this.constructor == f )
return new forwardedFunction();
else
forwardedFunction();
}
The good of it is that no object with f as a constructor will ever
escape that f, and that it breaks none of my code.
I can't see any way of ensuring that f.prototype is the first object
in the prototype chain, so the above can be tricked using, e.g.,
var fake = new f();
// fiddle with fake
f.call(fake); // can't see that fake is not a new object
So, is my f really fooled with this ?
Since fake.constructor == forwardedFunction, which implies
fake.constructor != f, I guess that forwardedFunction will be called,
and not newed. Unless I'm mistaken, of course.
The only "fiddling with fake" that I could find that messed things up
was to hack f construcotr property:
fake.constructor = f;
f.call(fake); // Ok, gotcha !
And since in my case, f is actually an anonymous inner function, this
fiddling is not possible.
So finally, here is my definite function interceptor, and I claim it is
bullet-proof (but would be interested in being proved wrong):
// richard cornford's "constructWithArgs":
var constructWithArgs = (function(){
function Dummy(){ ; }
return (function(fun, args){
Dummy.prototype = fun.prototype;
var tmp = new Dummy;
fun.apply(tmp, args);
return tmp;
})
})();
// precondition: obj[memberFunction] must be a function
function intercept( obj, memberFunction )
{
obj[memberFunction] = function() {
alert( "BEFORE call to " + memberFunction);
try
{
if( constructor == arguments.callee )
return constructWithArguments( obj[memberFunction], arguments );
else
return obj[memberFunction].apply( this, arguments );
}
finally
{
alert("AFTER call to " + memberFunction);
}
}
}
Actually I could make up one bullet:
intercept( this, "Array" );
a = new Array();
alert( a.constructor == Array ); // false !!
but it's not the interceptor that breaks, but the interceptor that
breaks outside code.
Indeed, there shouldn't be a way to see it. The "new" operator creates
the object, but the call to "f" to initialize it afterwards is just a
normal function call (calling the [[Call]] method of the function).
Well, I was imaginating in the wrong direction: I was somehow looking
for a way to determine whether 'this' was a fresh, new and immaculate
object. Dreaming out loud, I suppose.
Cheers,
Alexis