function identifier vs. arguments.callee

Discussion in 'Javascript' started by VK, Dec 29, 2006.

  1. VK

    VK Guest

    I was getting this effect N times but each time I was in rush to just
    make it work, and later I coudn't recall anymore what was the original
    state I was working around. This time I nailed the bastard so posting
    it before I forgot again...

    By taking this minimum code:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
    <html>
    <head>
    <title>Demo</title>
    <meta http-equiv="Content-Type"
    content="text/html; charset=iso-8859-1">
    <script type="text/javascript">

    // 1)
    (function refByCallee() {
    arguments.callee.foobar = 'foobar';
    })();

    // 2)
    (function refByName() {
    refByName.foobar = 'foobar';
    })();

    if (typeof refByCallee != 'undefined') {
    alert(typeof refByCallee.foobar); // undefined
    alert(typeof refByName.foobar); // string
    }
    </script>
    </head>
    <body>
    <h1>Demo</h1>
    </body>
    </html>

    There are two issues here: the one is well-known and another I what I
    want to ask about.

    1) The known issue is the difference of how JavaScript and JScript are
    treating function declarations within expression. In JScript it still
    leads to a function reference added to the global namespace, just as
    without any parenthesis.
    This way on IE after executing 1) and 2) we have two new global named
    functions while on other engines not.

    2) What I'm not sure is how to explain that IE obviously makes
    difference here between arguments.callee and literal name. While
    literal name acts as expected - see 2) - arguments.callee points to
    some other object instance disappearing right after the execution.

    Any insides?
     
    VK, Dec 29, 2006
    #1
    1. Advertising

  2. VK

    Jonas Raoni Guest

    VK escreveu:
    > I was getting this effect N times but each time I was in rush to just
    > make it work, and later I coudn't recall anymore what was the original
    > state I was working around. This time I nailed the bastard so posting
    > it before I forgot again...
    >
    > By taking this minimum code:
    >
    > <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
    > <html>
    > <head>
    > <title>Demo</title>
    > <meta http-equiv="Content-Type"
    > content="text/html; charset=iso-8859-1">
    > <script type="text/javascript">
    >
    > // 1)
    > (function refByCallee() {
    > arguments.callee.foobar = 'foobar';
    > })();
    > if (typeof refByCallee != 'undefined') {
    > alert(typeof refByCallee.foobar); // undefined
    > alert(typeof refByName.foobar); // string
    > }


    The bellow lines show you what happens (the "namedFunction" isn't the
    same object that is returned by the function declaration).

    var f = function namedFunction(){
    //alert(namedFunction === arguments.callee);
    //alert(f === arguments.callee);
    arguments.callee.property = '[I exist]';
    };
    namedFunction(); //using namedFunction as callee
    alert(namedFunction.property + "\n" + f.property);

    f(); //using f as callee
    alert(namedFunction.property + "\n" + f.property);


    --
    Jonas Raoni Soares Silva
    http://www.jsfromhell.com
     
    Jonas Raoni, Dec 29, 2006
    #2
    1. Advertising

  3. VK wrote:
    > I was getting this effect N times but each time I was in rush
    > to just make it work, and later I coudn't recall anymore what
    > was the original state I was working around.


    And you wonder why nobody takes you seriously when you label yourself a
    "programmer"?

    > This time I nailed the bastard so posting
    > it before I forgot again...


    Well, there is no hope that you could analyse this for yourself.

    > By taking this minimum code:
    >
    > <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
    > <html>
    > <head>
    > <title>Demo</title>
    > <meta http-equiv="Content-Type"
    > content="text/html; charset=iso-8859-1">


    "Minimum code" does not need a META element.

    > <script type="text/javascript">
    >
    > // 1)
    > (function refByCallee() {
    > arguments.callee.foobar = 'foobar';
    > })();
    >
    > // 2)
    > (function refByName() {
    > refByName.foobar = 'foobar';
    > })();
    >
    > if (typeof refByCallee != 'undefined') {
    > alert(typeof refByCallee.foobar); // undefined
    > alert(typeof refByName.foobar); // string
    > }
    > </script>
    > </head>
    > <body>
    > <h1>Demo</h1>
    > </body>
    > </html>
    >
    > There are two issues here: the one is well-known and
    > another I what I want to ask about.
    >
    > 1) The known issue is the difference of how JavaScript
    > and JScript are treating function declarations within
    > expression.


    There is no sense in "function declarations within expression". Programs
    and function bodies are made up of FunctionDeclarations and Statements
    (two mutually exclusive constructs), Expressions are components of
    Statements. The code above only features FunctionExpressions with
    optional Identifiers.

    > In JScript it still leads to a function reference added
    > to the global namespace,


    IE erroneously adds named properties referring to function objects to
    the Variable object for the execution context in which the
    FunctionExpressions with optional Identifiers appears. That is only the
    global object in the global execution context.

    > just as without any parenthesis.


    Without the parenthesise the constructs are unambiguously
    FunctionDeclaration (to every ECMAScript engine).

    > This way on IE after executing 1) and 2) we have two
    > new global named functions while on other engines not.


    On IE you actually have two named properties of the Variable object
    referring to function objects _before_ the execution of 1) and 2). And
    this fact is the biggest clue as to what IE is really doing when it
    misinterprets this code.

    > 2) What I'm not sure is how to explain that IE obviously
    > makes difference here between arguments.callee and literal
    > name.


    You mean a difference between the object referred to by -
    arguments.callee - and the object referred to by the Identifier.

    > While literal name acts as expected - see 2)


    It only acts as expected if you appreciate the bug in IE. The
    expectation derived from the language specification is that the
    Identifier used outside of the function bodies should not resolve into
    references to function objects, and inside the function bodies they
    should refer to the same object as - arguments.callee -. It is the
    difference between the formal specification that Microsoft assert
    JScript follows and the behaviour of JScript that allows this to be
    labelled a bug.

    > - arguments.callee points to some other object instance
    > disappearing right after the execution.


    The - arguments.callee - reference should refer to the function object
    that is being executed, and it does. As that function object results
    form the inline execution of a FunctionExpression and no reference to
    that function object is assigned to any property of any other object in
    the system you should expect that object to 'disappear' following its
    execution.

    Apart from failing to test for the existence of the properties of the
    Variable object prior to the execution of the FunctionExpressions (and
    so not noticing that they do exist, and refer to function objects, at
    that point), you have not verified that, for example, - refByCallee -
    and - arguemnts.callee - refer to the same object. The tests is simple:-

    alert('(callee === refByCallee) '+(arguments.callee === refByCallee));

    - and with:-

    (function fn() {
    alert('(callee === fn) '+(arguments.callee === fn));
    arguments.callee.foobar = 'foobar';
    })();

    - the result is false. The object referred to by the Identifier - fn -
    is not the same object as referred to by - arguments.callee - inside the
    executing function object.

    Meanwhile, with:-

    fn();

    (function fn() {
    alert('(callee === fn) '+(arguments.callee === fn));
    arguments.callee.foobar = 'foobar';
    })();

    fn();

    - the alerts are true, false and true (in that order). Prior to the
    evaluation of the FunctionExpression an - fn - function exists, can be
    called and is the object referred to by - arguments.callee - when it is
    executing. When the FunctionExpression is executed - argument.callee -
    does not refer to the - fn - function, and after the execution of the
    FunctionExpression a second call to the - fn - function again results in
    the execution of a function object that's - arguments.callee - refers to
    the - fn - function.

    The explanation for this is simply that there are two function objects
    involved; a function object that is referred to by the property of the
    Variable object and comes into existence prior to the execution of any
    code for the execution context, and a second function object that comes
    into existence as a result of the evaluation of the FunctionExpression.

    The function object coming into existence with the evaluation of the
    FunctionExpression is what is supposed to happen (the handling of the
    optional Identifier is still wrong on IE, but then optional Identifiers
    are not really expected to be used with FunctionExpressions). So it is
    the creation of the first function object that represents the
    manifestation of the bug in IE. The fact that these functions, and
    corresponding properties of the Variable object, come into existence
    prior to the execution of any code for the execution context suggests
    that the fault is in the variable instantiation stage of execution.
    Specifically, that at the point of scanning for function declarations IE
    is using criteria for identifying Function Declarations that are
    considerably more crude than the formal syntax rules for a
    FunctionDeclaration. That is, it is looking for the - function keyword
    followed by an Identifier followed by a matching set of braces and
    taking any occurrences of that, regardless of context, as a Function
    Declaration. And so finding, and acting upon, considerably more
    FunctionDeclarations than exist in the actual code.

    This probably represents an attempt at an optimisation for speed. It has
    been observed that IE is the fastest browser at parsing javascript
    source (by the fact that its - eval - function and - Function -
    constructor out perform all other environments) and being a bit lax on
    the syntax rules may be key to this.

    The consequences of this bug are largely insignificant as nobody should
    be writing code with the expectation that the optional Identifier in a
    FunctionExpression should be available outside of the resulting
    function, and so not be attempting to refer to that function in that
    way. Your own code, for example, is stupidly designed. If you wanted to
    refer to named global functions (to use them as a vehicle for passing
    data about) then it would be trivial (and more obvious) to have the
    function objects created globally with FunctionDeclarations. If stupidly
    obtuse code is written then it likely will fall over implementation
    bugs.

    Richard.
     
    Richard Cornford, Dec 29, 2006
    #3
  4. VK

    VK Guest

    Jonas Raoni wrote:
    > The bellow lines show you what happens (the "namedFunction" isn't the
    > same object that is returned by the function declaration).
    >
    > var f = function namedFunction(){
    > //alert(namedFunction === arguments.callee);
    > //alert(f === arguments.callee);
    > arguments.callee.property = '[I exist]';
    > };
    > namedFunction(); //using namedFunction as callee
    > alert(namedFunction.property + "\n" + f.property);
    >
    > f(); //using f as callee
    > alert(namedFunction.property + "\n" + f.property);


    Yes, I knew it already - but still thank you for answering. My question
    was what kind of object arguments.callee is in this case and what
    mechanics is behind.
     
    VK, Dec 30, 2006
    #4
  5. VK

    VK Guest

    charset for code snippets, was: function identifier vs. arguments.callee

    Richard Cornford wrote:
    > "Minimum code" does not need a META element.


    Not for a HTML source and especially not for a HTML with a script
    sample - unless one has a guarantee that the sample will be always
    first uploaded to a properly configured server setting charset in
    Content-Type header and only then viewed from that server.

    Otherwise IE users with View > Encoding > Auto-Select activated may hit
    the "Korean issue" while trying to execute the sample with the most
    strange results to expect. The results will be especially "visually
    impressive" if the current IE has Hangul (Korean phonemic alphabet)
    package installed :)

    Try this for instance on IE with Auto-Select activated:

    <html>
    <head>
    <title>Demo</title>
    </head>
    <body>
    <h1>+10-</h1>
    <script type="text/javascript">
    var foo = "a" + "A";
    alert(foo);
    </script>
    </body>
    </html>

    This way rather than being dependant on circumstances or checking each
    source for the "Korean issue vulnerability" one should *always* set
    META with matching charset. For the majority of simple demos ISO-8859-1
    does the needed trick.

    At the same time the existing standards do not require to place
    META-EQUIV with Content-Type on the page. This way the brave people are
    welcome to disregard this advice. They are even welcome do not set
    Content-Type anywhere at all because current RFCs specify default
    charset for both HTML and XML. I'm personally glad to see as many of
    such "standard informed" people as possible. This people is the
    quickest and easiest source of money for any help desk including ours
    :)
     
    VK, Dec 30, 2006
    #5
  6. VK

    VK Guest

    Richard Cornford wrote:
    > There is no sense in "function declarations within expression". Programs
    > and function bodies are made up of FunctionDeclarations and Statements
    > (two mutually exclusive constructs), Expressions are components of
    > Statements. The code above only features FunctionExpressions with
    > optional Identifiers.


    Thanks for your explanations which are snipped in this reply but which
    are gracefully read.

    In relevance to "bug" vs "behavior specific" the matter doesn't seem as
    straightforward as you stated IMHO. The question is whether function
    declaration
    function something() {
    }
    becomes function statement just because you have surrounded it by
    parenthesis:
    (function something() {
    })

    ?

    ECMA and Gecko seems thinking yes. Microsoft seems thinking no, and
    this point has some merit IMHO. Function object cannot be in the
    left-hand side of an expression. So in case like
    (function something() {
    })();
    we either have a syntaxically incorrect statement or
    FunctionDeclaration.

    You may shot now if you want to :) - I just expressed my worthless
    opinion :)
     
    VK, Dec 30, 2006
    #6
  7. VK wrote:
    > Richard Cornford wrote:
    >> There is no sense in "function declarations within expression".
    >> Programs and function bodies are made up of FunctionDeclarations
    >> and Statements (two mutually exclusive constructs), Expressions
    >> are components of Statements. The code above only features
    >> FunctionExpressions with optional Identifiers.

    >
    > Thanks for your explanations which are snipped in this reply
    > but which are gracefully read.


    Evidently much of it went straight over your head, which is not
    unexpected.

    > In relevance to "bug" vs "behavior specific" the matter
    > doesn't seem as straightforward as you stated IMHO.


    Your opinions are, as always, worthless. In this case you ignorance of
    the syntax rules for javascript, the related concepts, and your
    consequent inability to understand my explanation of the pertinent
    details, is the reason for that.

    > The question is whether
    > function declaration
    > function something() {
    > }
    > becomes function statement


    It is a FunctionExpression. The syntactic units relating to functions
    are FunctionDeclaration and FunctionExpression. Neither are Statements.
    FunctionDeclarations and Statements are the two types of component that
    make up Programs and function bodies, and so are mutually exclusive.
    Statements may contain Expressions and so may contain Function
    Expressions, though the syntax rules explicitly forbid the possibility
    of any Statement consisting of only a Function Expression (by excluding
    the function keyword from the possible tokens that may commence an
    ExpressionStatement).

    > just because you have surrounded it by
    > parenthesis:
    > (function something() {
    > })
    >
    > ?


    Surrounding the FunctionExpression with parenthesise does exactly that,
    as the only construct that may commence with an opening parenthesis
    token is an ExpressionStatement, the only Expression that may commence
    with an opening parenthesis is the "Grouping operator"
    PrimaryExpression, and the "Grouping operator" PrimaryExpression is only
    allowed to contain an Expression.

    Even if the opening parenthesis do not commence the Statement, that is,
    if they follow a MemberExpression and so would be interpreted as an
    Arguments List (forming a CallExpression) that Arguments List is still a
    list of zero or more Expressions.

    And so if you wrap parentheses around - function Identifier<opt> (
    FormalParameterList<opt> ) { FunctionBody } - you do guarantee that what
    you have just wrapped in parenthesise is a FunctionExpression (and so
    part of a Statement) and absolute not a FunctionDeclaration (as
    Statements and Function Declarations are mutually exclusive).

    > ECMA and Gecko seems thinking yes. Microsoft seems
    > thinking no,


    If Microsoft do not think that construct is a FunctionExpression why is
    JScript creating a new function object when it evaluates the Expression?

    > and this point has some merit IMHO.


    Your opinions are, as always, worthless.

    > Function object cannot be in the
    > left-hand side of an expression.


    Nonsense. Values that represent references to function objects (which is
    what a parenthesised FunctionExpression evaluates as) are always the
    left hand side of CallExpressions (that is, every successful
    function/method call that is ever executed). It is your habitual making
    ridiculous statements like that helps renders your opinions worthless.

    > So in case like
    > (function something() {
    > })();
    > we either have a syntaxically incorrect statement or
    > FunctionDeclaration.


    It is a syntactically correct CallExpression, and represents a
    syntactically correct ExpressionStatement.

    You are neglecting to take seriously the often observed fact that
    whenever you think something is the case the odds are better than 50/50
    that it is not the case. Try to understand; the stuff in your head has
    very little relationship with reality. You should not trust it.

    > You may shot now if you want to :) - I just expressed my
    > worthless opinion :)


    You certainly did. It may help you progress towards some sort of
    understanding of javascript is you did something about learning the
    syntax of the language instead of trying to make it up off the top of
    your head.

    Richard.
     
    Richard Cornford, Dec 31, 2006
    #7
  8. VK

    VK Guest

    Richard Cornford wrote:
    > Surrounding the FunctionExpression with parenthesise does exactly that,
    > as the only construct that may commence with an opening parenthesis
    > token is an ExpressionStatement, the only Expression that may commence
    > with an opening parenthesis is the "Grouping operator"
    > PrimaryExpression, and the "Grouping operator" PrimaryExpression is only
    > allowed to contain an Expression.


    With such magic power of parenthesis I could claim then my $1,000,000
    for positively solving Entscheidungsproblem. Because of
    FunctionExpression in JavaScript being a derivative case of lambda
    calculus, Entscheidungsproblem is solved as easy and elegant as:

    <html>
    <head>
    <title>Test</title>
    <meta http-equiv="Content-Type"
    content="text/html; charset=iso-8859-1">
    <script type="text/javascript">
    window.alert(
    (function a(){}) == (function b(){})
    );
    </script>
    </head>
    <body>
    <h1>Demo</h1>
    </body>
    </html>

    Take it as a New Year joke. Nappy New Year!
    :)
     
    VK, Dec 31, 2006
    #8
    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. Kobu
    Replies:
    7
    Views:
    468
  2. Replies:
    2
    Views:
    1,785
  3. Replies:
    2
    Views:
    918
    Owen Jacobson
    Dec 11, 2007
  4. Csaba  Gabor
    Replies:
    9
    Views:
    143
  5. -Lost
    Replies:
    12
    Views:
    281
    Elegie
    Jan 31, 2007
Loading...

Share This Page