Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Javascript > Using eval() for function definition

Reply
Thread Tools

Using eval() for function definition

 
 
Darko
Guest
Posts: n/a
 
      02-19-2007
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[i].onclick = function()
{ alert( this.values[i] ); };
}
}

However, this last code (makeHandlers() method) doesn't work since the
expression "this.values[i]" 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[i].onclick = eval( "function() { alert( " +
this.values[i] + "); }" );
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

 
Reply With Quote
 
 
 
 
Darko
Guest
Posts: n/a
 
      02-19-2007
On Feb 19, 4:56 pm, "Darko" <(E-Mail Removed)> 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[i].onclick = function()
> { alert( this.values[i] ); };
> }
>
> }
>
> However, this last code (makeHandlers() method) doesn't work since the
> expression "this.values[i]" 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[i].onclick = eval( "function() { alert( " +
> this.values[i] + "); }" );
> 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()
{ ...

 
Reply With Quote
 
 
 
 
Geoffrey Summerhayes
Guest
Posts: n/a
 
      02-19-2007
On Feb 19, 10:56 am, "Darko" <(E-Mail Removed)> 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[i].onclick = function()
> { alert( this.values[i] ); };
> }
>
> }
>


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[i].onclick=foo(this.values[i]);


---
Geoff

 
Reply With Quote
 
Darko
Guest
Posts: n/a
 
      02-19-2007
On Feb 19, 8:18 pm, "Geoffrey Summerhayes" <(E-Mail Removed)>
wrote:
> On Feb 19, 10:56 am, "Darko" <(E-Mail Removed)> 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[i].onclick = function()
> > { alert( this.values[i] ); };
> > }

>
> > }

>
> 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[i].onclick=foo(this.values[i]);
>
> ---
> 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

 
Reply With Quote
 
Richard Cornford
Guest
Posts: n/a
 
      02-19-2007
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[i].onclick = function()
> { alert( this.values[i] ); };


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[i]" 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[i].onclick = eval( "function() { alert( " +
> this.values[i] + "); }" );
> 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[i].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.

 
Reply With Quote
 
Darko
Guest
Posts: n/a
 
      02-20-2007
On Feb 19, 10:31 pm, "Richard Cornford" <(E-Mail Removed)>
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[i].onclick = function()
> > { alert( this.values[i] ); };

>
> 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[i].onclick = eval( "function() { alert( " +
> > this.values[i] + "); }" );
> > 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[i].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!

 
Reply With Quote
 
Richard Cornford
Guest
Posts: n/a
 
      02-20-2007
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.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Run-time template list definition / Run-time variable type definition Pierre Yves C++ 2 01-10-2008 02:52 PM
Automagic determination of definition based on definition location. Jon Slaughter C++ 4 10-26-2005 05:00 PM
can a class definition inside another class's definition Jianli Shen C++ 1 03-13-2005 06:02 PM
help?: incomplete definition with complete definition in scope Ark C Programming 1 08-07-2004 04:21 PM
Function definition into main() function. CViniciusM C Programming 2 02-27-2004 03:39 PM



Advertisments