By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,537 Members | 1,743 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,537 IT Pros & Developers. It's quick & easy.

Using eval() for function definition

P: n/a
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

Feb 19 '07 #1
Share this Question
Share on Google+
7 Replies


P: n/a
On Feb 19, 4:56 pm, "Darko" <darko.maksimo...@gmail.comwrote:
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()
{ ...

Feb 19 '07 #2

P: n/a
On Feb 19, 10:56 am, "Darko" <darko.maksimo...@gmail.comwrote:
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

Feb 19 '07 #3

P: n/a
On Feb 19, 8:18 pm, "Geoffrey Summerhayes" <sumr...@hotmail.com>
wrote:
On Feb 19, 10:56 am, "Darko" <darko.maksimo...@gmail.comwrote:
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

Feb 19 '07 #4

P: n/a
On Feb 19, 8:14 am, "Darko" <darko.maksimo...@gmail.comwrote:
On Feb 19, 4:56 pm, "Darko" <darko.maksimo...@gmail.comwrote:
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()
{ ...
First off: using "eval" in this context is completely inappropriate.
For one thing, you have the "Function" constructor which works in much
the same way; for another, a proper understanding of closures will
help to avoid this problem.

You have inadvertently touched on one of the more advanced topics in
javascript: closures and "this" keyword resolution. Understanding
this is key to using mature JavaScript technique. Please read this
article:

http://www.jibbering.com/faq/faq_notes/closures.html (by this list's
own Richard Cornford)

and then come back if you still have questions.

-David

Feb 19 '07 #5

P: n/a
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.

Feb 19 '07 #6

P: n/a
On Feb 19, 10:31 pm, "Richard Cornford" <Rich...@litotes.demon.co.uk>
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!

Feb 20 '07 #7

P: n/a
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.

Feb 20 '07 #8

This discussion thread is closed

Replies have been disabled for this discussion.