Perfect function forwarding

Discussion in 'Javascript' started by Alexis Nikichine, Dec 27, 2005.

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

    --
    Some domain is free
     
    Alexis Nikichine, Dec 27, 2005
    #1
    1. Advertising

  2. Alexis Nikichine wrote:

    > --
    > Some domain is [...]


    somedomain.fr is not. Yet.

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


    PointedEars
     
    Thomas 'PointedEars' Lahn, Dec 27, 2005
    #2
    1. Advertising

  3. Alexis Nikichine wrote in news:43b17beb$0$21746$ 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.
    --
    http://www.victim-prime.dsl.pipex.com/
     
    Rob Williscroft, Dec 27, 2005
    #3
  4. Rob Williscroft wrote:

    > 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
     
    Thomas 'PointedEars' Lahn, Dec 27, 2005
    #4
  5. Alexis Nikichine

    Randy Webb Guest

    Thomas 'PointedEars' Lahn said the following on 12/27/2005 1:27 PM:
    > Alexis Nikichine wrote:
    >
    >
    >>--
    >>Some domain is [...]

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

    --
    Randy
    comp.lang.javascript FAQ - http://jibbering.com/faq & newsgroup weekly
    Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
     
    Randy Webb, Dec 27, 2005
    #5
  6. Alexis Nikichine <> writes:

    > 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
    --
    Lasse Reichstein Nielsen -
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
    'Faith without judgement merely degrades the spirit divine.'
     
    Lasse Reichstein Nielsen, Dec 28, 2005
    #6
  7. Lasse Reichstein Nielsen wrote:

    > 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
     
    Alexis Nikichine, Dec 28, 2005
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Scott Meyers
    Replies:
    6
    Views:
    971
    Scott Meyers
    Dec 5, 2010
  2. Scott Meyers
    Replies:
    20
    Views:
    1,112
    itaj sherman
    Mar 16, 2011
  3. Andrew Tomazos
    Replies:
    1
    Views:
    1,003
    Andrew Tomazos
    Dec 23, 2011
  4. dervih
    Replies:
    3
    Views:
    509
    dervih
    Jul 13, 2012
  5. Replies:
    3
    Views:
    342
Loading...

Share This Page