Using eval() for function definition

Discussion in 'Javascript' started by Darko, Feb 19, 2007.

  1. Darko

    Darko Guest

    Hello,

    I have this particular problem with eval() when using Microsoft
    Internet Explorer, when trying to define an event handler. This is the
    code:

    function BigObject()
    {
    this.items = new Array();
    this.values = new Array();

    this.addItem = function( item )
    {
    this.items[this.items.length] = item;
    }

    this.makeHandlers()
    {
    var i, length = this.items.length;
    for ( i = 0; i < length; i++ )
    this.items.onclick = function()
    { alert( this.values ); };
    }
    }

    However, this last code (makeHandlers() method) doesn't work since the
    expression "this.values" automatically belongs to this new
    anonymous function, and therefore isn't valid (since the new anonymous
    function(s) don't have the "values" attribute. So I tried the
    following:
    this.items.onclick = eval( "function() { alert( " +
    this.values + "); }" );
    and it worked! ... in Firefox only :( Internet explorer returns
    "undefined" for eval( "function() { /* whatever */ ); } " ), for the
    same things Firefox perfectly understands, and if I try to make it a
    handler, an exception is fired in IE. What do I do? Did I come to the
    right conclusion with IE or am I making a banal mistake? Do I need to
    find another way of solving this or is there a fix to this solution?

    Thank you,
    Darko
     
    Darko, Feb 19, 2007
    #1
    1. Advertising

  2. Darko

    Darko Guest

    On Feb 19, 4:56 pm, "Darko" <> wrote:
    > Hello,
    >
    > I have this particular problem with eval() when using Microsoft
    > Internet Explorer, when trying to define an event handler. This is the
    > code:
    >
    > function BigObject()
    > {
    > this.items = new Array();
    > this.values = new Array();
    >
    > this.addItem = function( item )
    > {
    > this.items[this.items.length] = item;
    > }
    >
    > this.makeHandlers()
    > {
    > var i, length = this.items.length;
    > for ( i = 0; i < length; i++ )
    > this.items.onclick = function()
    > { alert( this.values ); };
    > }
    >
    > }
    >
    > However, this last code (makeHandlers() method) doesn't work since the
    > expression "this.values" automatically belongs to this new
    > anonymous function, and therefore isn't valid (since the new anonymous
    > function(s) don't have the "values" attribute. So I tried the
    > following:
    > this.items.onclick = eval( "function() { alert( " +
    > this.values + "); }" );
    > and it worked! ... in Firefox only :( Internet explorer returns
    > "undefined" for eval( "function() { /* whatever */ ); } " ), for the
    > same things Firefox perfectly understands, and if I try to make it a
    > handler, an exception is fired in IE. What do I do? Did I come to the
    > right conclusion with IE or am I making a banal mistake? Do I need to
    > find another way of solving this or is there a fix to this solution?
    >
    > Thank you,
    > Darko


    I'm sorry, I had a syntax error in the post I submitted, just in case
    someone thinks that is the reason for my troubles, it isn't - it was a
    typo just in the post here:
    this.makeHandlers()
    { ...
    should have been written:
    this.makeHandlers = function()
    { ...
     
    Darko, Feb 19, 2007
    #2
    1. Advertising

  3. On Feb 19, 10:56 am, "Darko" <> wrote:
    > Hello,
    >
    > I have this particular problem with eval() when using Microsoft
    > Internet Explorer, when trying to define an event handler. This is the
    > code:
    >
    > function BigObject()
    > {
    > this.items = new Array();
    > this.values = new Array();
    >
    > this.addItem = function( item )
    > {
    > this.items[this.items.length] = item;
    > }
    >
    > this.makeHandlers()
    > {
    > var i, length = this.items.length;
    > for ( i = 0; i < length; i++ )
    > this.items.onclick = function()
    > { alert( this.values ); };
    > }
    >
    > }
    >


    Same thing happens in Lisp:
    CL-USER: (let ((foo #1A(1 2 3)))
    (funcall (car (loop for i below 3 collect (lambda() (aref
    foo i))))))

    Error: The subscript 3 exceeds the limit 2 for the first dimension
    of the array #(1 2 3).
    1 (abort) Return to level 0.
    2 Return to top loop level 0.

    You're not creating the closure you think you are,
    it is binding on i. What you are getting is

    function(){alert(this.values[length]);}

    for all of them because i=length at the end of
    the loop.

    Try this, create a function

    function foo(x){return function(){alert(x)}}

    and use

    this.items.onclick=foo(this.values);


    ---
    Geoff
     
    Geoffrey Summerhayes, Feb 19, 2007
    #3
  4. Darko

    Darko Guest

    On Feb 19, 8:18 pm, "Geoffrey Summerhayes" <>
    wrote:
    > On Feb 19, 10:56 am, "Darko" <> wrote:
    >
    >
    >
    > > Hello,

    >
    > > I have this particular problem with eval() when using Microsoft
    > > Internet Explorer, when trying to define an event handler. This is the
    > > code:

    >
    > > function BigObject()
    > > {
    > > this.items = new Array();
    > > this.values = new Array();

    >
    > > this.addItem = function( item )
    > > {
    > > this.items[this.items.length] = item;
    > > }

    >
    > > this.makeHandlers()
    > > {
    > > var i, length = this.items.length;
    > > for ( i = 0; i < length; i++ )
    > > this.items.onclick = function()
    > > { alert( this.values ); };
    > > }

    >
    > > }

    >
    > Same thing happens in Lisp:
    > CL-USER: (let ((foo #1A(1 2 3)))
    > (funcall (car (loop for i below 3 collect (lambda() (aref
    > foo i))))))
    >
    > Error: The subscript 3 exceeds the limit 2 for the first dimension
    > of the array #(1 2 3).
    > 1 (abort) Return to level 0.
    > 2 Return to top loop level 0.
    >
    > You're not creating the closure you think you are,
    > it is binding on i. What you are getting is
    >
    > function(){alert(this.values[length]);}
    >
    > for all of them because i=length at the end of
    > the loop.
    >
    > Try this, create a function
    >
    > function foo(x){return function(){alert(x)}}
    >
    > and use
    >
    > this.items.onclick=foo(this.values);
    >
    > ---
    > Geoff


    It actually worked! Thank you a lot! I thought about a similar way,
    creating a function object that would receive arguments, and generated
    a function, but the way I did it couldn't help neither. This is
    perfect, thank you!

    Darko
     
    Darko, Feb 19, 2007
    #4
  5. Darko wrote:
    > I have this particular problem with eval() when using
    > Microsoft Internet Explorer, when trying to define an
    > event handler. This is the code:
    >
    > function BigObject()
    > {
    > this.items = new Array();
    > this.values = new Array();
    >
    > this.addItem = function( item )
    > {
    > this.items[this.items.length] = item;
    > }


    This - addItem - method does not take advantage of its status as an inner
    function (its unique identify and the closure resulting form its
    assignment). Under those circumstances it would be better to assign it to
    the - BigObject.protoype - so a single function object may be shared as
    an instance method of all - BigObject - instances.

    > this.makeHandlers()


    Noting the correction; this.makeHandlers = function()

    > {
    > var i, length = this.items.length;
    > for ( i = 0; i < length; i++ )
    > this.items.onclick = function()
    > { alert( this.values ); };


    In javascript the value of the - this - keyword is determined by how a
    function is called. It is not a property of the function objects
    themselves. In response to events, a browser calls the functions assigned
    to its intrinsic event properties as methods of the DOM Element to which
    the handler is assigned, this leaves the - this - keyword referring to
    the DOM Element.

    > }


    This method makes no use of its status as an inner function and so should
    again be assigned to the prototype.

    > }
    >
    > However, this last code (makeHandlers() method) doesn't work
    > since the expression "this.values" automatically belongs
    > to this new anonymous function,


    No, it doesn't work because - this - refers to the DOM Element and the -
    i - value belongs to the one containing execution and has the value it
    had when the - for - loop finished.

    > and therefore isn't valid (since the new anonymous
    > function(s) don't have the "values" attribute.


    They don't, but it is the DOM Element not having a - values - property
    that is significant here.

    > So I tried the following:
    > this.items.onclick = eval( "function() { alert( " +
    > this.values + "); }" );
    > and it worked!


    It would be more accurate to say that where it 'worked' it actually
    failed to fail as expected. The - eval - function executes its string
    argument as a complete javascript Program, and the units that a Program
    can be made up of are Statements and FunctionDeclarations. A
    FunctionDeclaration must have an Identifier as the function name, so your
    string is not a syntactically correct FunctionDeclaration. A statement
    may not start with the - function - keyword, so your string is not a
    syntactically correct Statement, and so it also cannot be a syntactically
    correct javascript Program.

    A combination of using - eval - (which often acts to mask errors, or make
    them indirect/obscure) , syntax extensions and error tolerance
    (particularly in IE's case) may conspire to give the impression of
    something that 'works', but there is nothing in the language to suggest
    that this would ever be effective code to be writing.

    > ... in Firefox only :( Internet explorer returns
    > "undefined" for eval( "function() { /* whatever */ ); } " ),
    > for the same things Firefox perfectly understands, and if I
    > try to make it a handler, an exception is fired in IE.


    You are not allowed to assign the undefined value to an intrinsic event
    property in IE.

    > What do I do?

    <snip>

    First, learning javascript's syntax might be of some use while attempting
    to write it.

    You need to have a function that is called as a method of a DOM element
    reference a property of a particular javascript object instance, and
    employ an individual and unique index with that property. The following
    will do that, but you will have to look at the URL reference to
    understand why:-

    function BigObject(){
    this.items = new Array();
    this.values = new Array();
    }
    BigObject.prototype.addItem = function(item){
    this.items[this.items.length] = item;
    };
    BigObject.prototype.makeHandlers = function(){
    var i, length = this.items.length;
    var self = this; // Make the object instance available on the scope
    // chain as a - self - variable.
    for ( i = 0; i < length; i++ ){
    this.items.onclick = (function(index){
    return (function(){
    alert( self.values[index] ); // self - is resolved
    // against the scope
    // chain, and resolves as
    // a reference to the
    // individual javascript
    // object instance
    // assigned in the
    // outermost function with
    // the - this - keyword.
    });
    })(i); // Pass the individual index - i - as an argument to the
    // function call that returns the event handling
    // function. This allows the event handling function to
    // reference its index as the outer unction's - index -
    // formal parameter.
    }
    };


    See:-
    <URL: http://jibbering.com/faq/faq_notes/closures.html >

    Richard.
     
    Richard Cornford, Feb 19, 2007
    #5
  6. Darko

    Darko Guest

    On Feb 19, 10:31 pm, "Richard Cornford" <>
    wrote:
    > Darko wrote:
    > > I have this particular problem with eval() when using
    > > Microsoft Internet Explorer, when trying to define an
    > > event handler. This is the code:

    >
    > > function BigObject()
    > > {
    > > this.items = new Array();
    > > this.values = new Array();

    >
    > > this.addItem = function( item )
    > > {
    > > this.items[this.items.length] = item;
    > > }

    >
    > This - addItem - method does not take advantage of its status as an inner
    > function (its unique identify and the closure resulting form its
    > assignment). Under those circumstances it would be better to assign it to
    > the - BigObject.protoype - so a single function object may be shared as
    > an instance method of all - BigObject - instances.

    The other day I saw in some script the prototype thing, I didn't
    really understand what it was for, now I understand a little better,
    and the links you gave to me seem to contain more about the issue;
    I'll have to give it a closer look. Anyway, sounds like a good idea to
    share the function definition among all the function-objects.

    >
    > > this.makeHandlers()

    >
    > Noting the correction; this.makeHandlers = function()
    >
    > > {
    > > var i, length = this.items.length;
    > > for ( i = 0; i < length; i++ )
    > > this.items.onclick = function()
    > > { alert( this.values ); };

    >
    > In javascript the value of the - this - keyword is determined by how a
    > function is called. It is not a property of the function objects
    > themselves. In response to events, a browser calls the functions assigned
    > to its intrinsic event properties as methods of the DOM Element to which
    > the handler is assigned, this leaves the - this - keyword referring to
    > the DOM Element.


    How stupid of me. Of course it's the element the event is about that
    the "this" attribute is of, I have already been using it, just didn't
    recognise the relation, I completely lost it.

    > This method makes no use of its status as an inner function and so should
    > again be assigned to the prototype.
    >
    > > }
    > > So I tried the following:
    > > this.items.onclick = eval( "function() { alert( " +
    > > this.values + "); }" );
    > > and it worked!

    >
    > It would be more accurate to say that where it 'worked' it actually
    > failed to fail as expected. The - eval - function executes its string
    > argument as a complete javascript Program, and the units that a Program
    > can be made up of are Statements and FunctionDeclarations. A
    > FunctionDeclaration must have an Identifier as the function name, so your
    > string is not a syntactically correct FunctionDeclaration. A statement
    > may not start with the - function - keyword, so your string is not a
    > syntactically correct Statement, and so it also cannot be a syntactically
    > correct javascript Program.

    I don't quite understand what you mean when you say a statement may
    not start with the function keyword? How is that? How about function
    definitions?

    > First, learning javascript's syntax might be of some use while attempting
    > to write it.

    Yes, well, I have learnt the 'var' and 'if' keywords, and something
    about semicolons, I thought that might do it? ;-)

    > function BigObject(){
    > this.items = new Array();
    > this.values = new Array();}
    >
    > BigObject.prototype.addItem = function(item){
    > this.items[this.items.length] = item;};
    >
    > BigObject.prototype.makeHandlers = function(){
    > var i, length = this.items.length;
    > var self = this; // Make the object instance available on the scope
    > // chain as a - self - variable.
    > for ( i = 0; i < length; i++ ){
    > this.items.onclick = (function(index){
    > return (function(){
    > alert( self.values[index] ); // self - is resolved
    > // against the scope
    > // chain, and resolves as
    > // a reference to the
    > // individual javascript
    > // object instance
    > // assigned in the
    > // outermost function with
    > // the - this - keyword.
    > });
    > })(i); // Pass the individual index - i - as an argument to the
    > // function call that returns the event handling
    > // function. This allows the event handling function to
    > // reference its index as the outer unction's - index -
    > // formal parameter.
    > }
    > > };


    Why, thank you a lot! This code was easily conceivable, with the
    comments of course, and I took a look in that text, it's bookmarked
    all right :) Thanks to you once again!
     
    Darko, Feb 20, 2007
    #6
  7. On Feb 20, 2:23 pm, Darko wrote:
    > On Feb 19, 10:31 pm, Richard Cornford wrote:
    >> Darko wrote:

    <snip>
    >>> and it worked!

    >
    >> It would be more accurate to say that where it 'worked' it actually
    >> failed to fail as expected. The - eval - function executes its string
    >> argument as a complete javascript Program, and the units that a
    >> Program can be made up of are Statements and FunctionDeclarations.
    >> A FunctionDeclaration must have an Identifier as the function name,
    >> so your string is not a syntactically correct FunctionDeclaration. A
    >> statement may not start with the - function - keyword, so your string
    >> is not a syntactically correct Statement, and so it also cannot be a
    >> syntactically correct javascript Program.

    >
    > I don't quite understand what you mean when you say a statement may
    > not start with the function keyword? How is that? How about function
    > definitions?

    <snip>

    The units of a javascript program are FunctionDeclarations and
    Statements. What you are calling a function definition would be the
    structure that qualifies as a Function Declaration, and so _not_ a
    Statement. The only form of statement that could commence with the -
    function - keyword is an ExpressionStatement, and the syntax rules for
    the ExpressionStatement explicitly forbid it from commencing with an
    opening brace ("{") or the - function - keyword. This is probably to
    avoid the result being ambiguous (making it clear that an
    ExpressionStatement is not either a Function Declaration or an object
    literal).

    Richard.
     
    Richard Cornford, Feb 20, 2007
    #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. Eric Newton
    Replies:
    3
    Views:
    9,591
    Brock Allen
    Apr 4, 2005
  2. DataBinder.Eval and Eval.

    , Jun 16, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    577
    Karl Seguin [MVP]
    Jun 16, 2006
  3. vasudevram
    Replies:
    6
    Views:
    351
    vasudevram
    Jun 24, 2007
  4. Alex van der Spek

    eval('07') works, eval('08') fails, why?

    Alex van der Spek, Jan 8, 2009, in forum: Python
    Replies:
    6
    Views:
    1,543
    Bruno Desthuilliers
    Jan 8, 2009
  5. Liang Wang
    Replies:
    8
    Views:
    152
    Ben Morrow
    Feb 2, 2008
Loading...

Share This Page