Perfect function forwarding

A

Alexis Nikichine

Hello,

Today, I have a function:

function f()
{
}


and am looking for a way of distinguishing, from inside f, whether it
has been called with new, or not.

function f()
{
if( ... )
return new forwardedFunction(...);
else
return forwardedFunction();
}

Iow, are we [[Call]]ed or [[Construct]]ed. Can't get around it...

Any help appreciated,

Alexis
 
R

Rob Williscroft

Alexis Nikichine wrote in in
comp.lang.javascript:

[snip]
and am looking for a way of distinguishing, from inside f, whether it
has been called with new, or not.

function f()
{
if( ... )
return new forwardedFunction(...);
else
return forwardedFunction();
}

Iow, are we [[Call]]ed or [[Construct]]ed. Can't get around it...

var GLOBAL = this;
function f()
{
alert( this === GLOBAL );
}

f();
new f();

Rob.
 
T

Thomas 'PointedEars' Lahn

Rob said:
Alexis Nikichine wrote [...]:
and am looking for a way of distinguishing, from inside f, whether it
has been called with new, or not.

function f()
{
if( ... )
return new forwardedFunction(...);
else
return forwardedFunction();
}

Iow, are we [[Call]]ed or [[Construct]]ed. Can't get around it...

var GLOBAL = this;
function f()
{
alert( this === GLOBAL );
}

f();
new f();

this == GLOBAL

should suffice. However, either test does not work for functions called
from non-global method context.


PointedEars
 
R

Randy Webb

Thomas 'PointedEars' Lahn said the following on 12/27/2005 1:27 PM:
Alexis Nikichine wrote:



somedomain.fr is not. Yet.

<URL:http://www.interhack.net/pubs/munging-harmful/>

Are you actually to the point in life where you have nothing better to
do than pedantically whine about a snippet in a signature?

It might not be so bad if you would reference a decent article instead
of an outdate worthless reference.

None of which is relevant or even remotely related to this thread and/or
this Newsgroup.
 
L

Lasse Reichstein Nielsen

Alexis Nikichine said:
Today, I have a function:

function f()
{
}
and am looking for a way of distinguishing, from inside f, whether it
has been called with new, or not.

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

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

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).

/L
 
A

Alexis Nikichine

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top