PDA

View Full Version : eval()...pros and cons


HairyTeeth
05-17-2003, 08:53 AM
I read a recently that eval() should be avoided. I'm wondering why?
Is eval() a cpu-vampire? If so, does it matter (considering the client-side processing power we have these days) and what would the alternative(s) be?

Interested because I've used it rather heavily in a script just recently.

liorean
05-17-2003, 11:03 AM
I've done some benchmarking on using eval('document.images.'+sName) versus document.images[sName]. I've found eval to take about 12 times the time the associative array takes in op7 (op6 had a radically different scripting engine where everything took much more time, but the comparison made eval just 1.5 times slower), 2.5 times in moz, 5 times in ie, 7.5 in nn4.

Eval also is a really hungry memory eater while executing.

Depending on what you use eval for, you can often replace it with more efficient code. If you ask for an eval-free version of your code, we might be able to replace it. (Depending on what you use eval for, you replace it with different code. Associative arrays are the most usual replacement.)

ez4ne12c
05-17-2003, 12:51 PM
Ive had some serious quoting headaches with eval
eventually i got round them but this can be a problem
since then i have avoided eval where i can
but sometimes i find i really want to use it

ez

cheesebagpipe
05-17-2003, 03:42 PM
You can use the [] operator, however, because it uses a string value (which is dynamic and can change at run-time), rather than an identifier (which static and must be hard-coded in the program), to name the property.
When an object is used this fashion, it is often called an associative array--a data structure that allows you to dynamically associate arbitrary data values with arbitrary strings. JavaScript objects are actually implemented internally as associative arrays. The . notation for accessing properties makes them seem like the static objects of C++ and Java, and they work perfectly well in that capacity. But they also have the very powerful ability to associate values with arbitrary strings. In this respect, JavaScript objects are much more like Perl arrays than like C++ or Java objects. David Flanagan, Javascript: The Definitive Guide (http://www.forerunners.org/WebLibrary/jscript/ch07_06.htm) (O'Reilly)



You can see that JavaScript's hashtable notation is very similar to Java's object and array notations. JavaScript takes this much farther: objects and hashtables are the same thing... Douglas Crockford, crockford.com (http://www.crockford.com/javascript/survey.html)

HairyTeeth
05-18-2003, 12:51 AM
I use eval() primarily for building cross-browser object references:

//globals;
var doc=""
var sty=""

//browser detection;
var nav4 = (document.layers)?1:0;


if(nav4){
doc="document.";
sty="";
}

//form valid object reference;
//I got this via Danny Goodman;
function getObj(obj){
var theObj;
if(typeof obj == "string"){
theObj = eval(doc + obj + sty);
} else {
theObj = obj;
}
return theObj;
}

function show(obj){
var theObj = getObj(obj);
theObj.visibility="visible";
}

A call...

<a href="javascript: show('theDiv')">Show</a>

But I've recently used eval() to reference a dynamically written textbox (for an online order form):

for(i=0;i<itemArray.length;i++){
var qty =eval("document.frm.quantity_"+i+".value");
var itemTotal = parseInt(qty) * parseFloat(itemArray[i].unitPrice);

The script will fire with the onchange event handler (when a user enters a quantity in the quantity_n textbox.

I don't know of another way to reference the textbox (?).

I've also made heavy use of innerHTML to write and get product values, which I'm now reconsidering in light of recent comments in another thread.

cheesebagpipe
05-18-2003, 01:15 AM
for(i=0;i<itemArray.length;i++){
var qty =document.frm['quantity_' + i].value;

Click on the D. Flanagan link above for an explanation. Haven't seen that Danny Goodman bit in years..."cross-browser" used to mean Navigator || MSIE v.4/5. Not any more. There are more systematic (:: library:: ) ways of doing these sorts of things than the reinventing the wheel approach every time you code, imo.

http://www.scottandrew.com/weblog/dhtmllibs

HairyTeeth
05-18-2003, 01:25 AM
lol, i tried

var qty =document.frm['quantity_' + i].value;

..but i got an error (a typo on my part) and now it works! DOH.
[EDIT: I'm such an idiot at times]

Thanks for the links, I'll check them out. :thumbsup:

cheesebagpipe
05-18-2003, 01:56 AM
At it again? (http://www.yuckitup.com/drunkcat.jpg) :rolleyes:

HairyTeeth
05-18-2003, 05:14 AM
LMAO. As it happens, No. I just have idiocy spams on a regular basis. It's a burden I must carry and (unfortunately for others) share. :)

mordred
05-19-2003, 02:30 AM
FWIW, here's a page that covers the square-bracket notation used to access an object's properties in detail. Quite useful for anyone who wants to get rid of unnecessary eval()s in their code.
http://www.litotes.demon.co.uk/js_info/sq_brackets.html

cheesebagpipe
05-19-2003, 03:25 AM
Nice. The only thing there seems to be disagreement on is this:In a web browser the global object is the window (or frame) in which the script is running. Each window (or frame) object contains a number of properties, at least two of which are references to the window (global object) itself. These properties are 'window' and 'self'.&nbsp;&nbsp;&nbsp;R. CornfordThe Global Object is the keeper of all of the functions and variables which were not defined inside of other functions and objects. Surprisingly, the Global Object does not have an explicit name in the language. Sometimes the this variable points at it, but often not. In the web browsers, window and self are members of the Global Object which point to the Global Object, thus giving an indirect way of addressing it...&nbsp;&nbsp;&nbsp;D. Crockford

Some other interesting links discovered recently:

http://w3future.com/html/stories/hop.xml
http://w3future.com/html/stories/callbacks.xml

liorean
05-19-2003, 12:54 PM
Well, it's true the globabl object doesn't have a name in the language. That's why window is mapped not only to the interface, but also as the global object. If you use JavaScript other than in a browser, you won't find window unless it's written to be browser-script compatible.

brothercake
05-19-2003, 02:37 PM
Originally posted by HairyTeeth
I use eval() primarily for building cross-browser object references
...
But I've recently used eval() to reference a dynamically written textbox (for an online order form)
Both of these are improper uses of eval() - eval to create an object reference from a string is deprecated and should not be used.

HairyTeeth
05-19-2003, 03:06 PM
I think I'm getting over this associative array blind spot I have. Thanks everyone.

Brothercake: I'm converted.

Liorean: how do you benchmark? Do you use a timestamp?

Cheesebagpipe and Mordred: excellent links! I found a good cross-browser library at cross-browser.com .

A question. Under what circumstances should eval() be used?

Thanks again people.

beetle
05-19-2003, 03:15 PM
About the only time I use eval() is when fuddling around - never for production scripting

var sum = eval( [1,2,3,4].join('+') );

Vladdy
05-19-2003, 03:34 PM
I still have not found a case when I could not do without eval... actually I never even came close to considering it.

brothercake
05-19-2003, 03:45 PM
I once used it to call a body onload event

eval(document.getElementsByTagName('body')[0].getAttribute('onload'));

which is a fair use, but probably not the best way of doing that, or the best use of eval.

liorean
05-19-2003, 04:37 PM
Nope, certainly not the best approach. You could have used (typeof document.body.onload=='undefined')?window.onload():document.body.onload().

beetle
05-19-2003, 05:49 PM
Okay, here's a tough one.

Here's the setup

function CustomObj()
{
// empty constructor
}

CustomObj.prototype.blue = function( param1, param2 )
{
alert( ['blue',param1,param2].join("\n") );
}

CustomObj.prototype.red = function( param1, param2, param3 )
{
alert( [red,param1,param2,param3].join("\n") );
}

function init()
{
var arr = ['red','blue'];
var params = ['one','two','three'];
var obj = new CustomObj();

for ( var i = 0; i < arr.length; i++ )
{
/* Your code here */
}
}
What needs to happen: You code needs to call the method(s) of CustomObj and send the params array as individual parameters, not as an array. How would you implement this without a serialized piece of code, such as eval() or the Function constructor?

Danne
05-19-2003, 06:19 PM
So, is there a better way to get a multidimensional array out of a string?

Ex:

var arr=eval('["item","item","item",["item","item",["item","item"],"item"],["item","item"]]');

beetle
05-19-2003, 06:28 PM
Originally posted by Danne
So, is there a better way to get a multidimensional array out of a string?Eh? That's already an array
var arr =
[
"item",
"item",
"item",
[
"item",
"item",
[
"item",
"item"
],
"item"
],
[
"item",
"item"
]
];I just don't understand why you'd have a string that's already in literal array notation.

Danne
05-19-2003, 07:10 PM
Oh, sorry, maybe a nice example would be in order...

This is actually meant for JScript in ASP:
I have a generic component for processing request which receives two request-parameters; Objects and Trans.

Objects are sent in a serialized way and mounted on serverside into the correct objects. A better example would be:
'[Recipe,[["1","Apple Pie",[["Dough",[["Wheat Flour",200]],["Stuffing",[["Pealed apple",200]]]]]]]'

would generate a Recipe object on serverside, which is a lot easier to work with than a complex array;
recipe.id: 1
recipe.name: "Apple Pie"
recipe.steps[0].name:"Dough"
recipe.steps[0].ingredients[0].name: "Wheat Flour"
recipe.steps[0].ingredients[0].qtde: 200
...

The recipe object is defined on both client and serverside.


So how can I generate an array from the string

'[Recipe,[["1","Apple Pie",[["Dough",[["Wheat Flour",200]],["Stuffing",[["Pealed apple",200]]]]]]]'

in better way than using eval?

ahosang
05-19-2003, 09:02 PM
beetle:

function init()
{
var arr = ['red','blue'];
var params = ['one','two','three'];
var obj = new CustomObj();

for ( var i = 0; i < arr.length; i++ )
{
obj[arr[i]].apply(obj, params);
}
}

beetle
05-19-2003, 09:12 PM
Thanks ahosang - but I acutally am familiar with apply() - only it's not supported in IE until version 6.0. I need at least 5.0 compatibility.

I could prototype it, but I'd still need to implement the function call as a string.

liorean
05-19-2003, 10:01 PM
Yah, I've had that problem too, with sending an expanded array instead of the array itself. I wrote a function to handle such calls, but it only allowed 1-12 arguments. The problem is that there's no expanding in JavaScript except for using Function object or eval. Both are evil. Function is a bit more versatile, though.

beetle
05-20-2003, 12:23 AM
I've used the Function constructor in my update of fValidate to elminate this horrendously large switch...case it used to use. Now I just serialize the array and evaluate the method call via my new function. It's not perfect, but it's a win over my previous setup, as far as I'm concerned.

ahosang
05-20-2003, 01:13 AM
beetle,
I'm sure you have a reason, but why are you trying to send an array as parameter to a function which you(?) have defined to take two strings?? Couldn't you just alter the definition of blue and red, so they can take a single array param as well?

beetle
05-20-2003, 01:40 AM
It's meant to aid in readability/brevity, speed up development, and aid in extendability. I'd much rather receive named parameters than one array and dissect it from the method. Without expanding the array prior to calling the method - the only other choice is to handle this process manually - which is quite verbose.

liorean
05-20-2003, 03:46 PM
Beetle, why not send an object literal instead, and craft the recieving function to that? The ability to send object literals makes functions really powerful.

liorean
05-20-2003, 03:50 PM
Hairy teeth:var
i=100000,
dStart=new Date;
while(i-->0)
/* actions to take*/
alert(new Date-dStart);
Or rather an object oriented variation of it. I've been using different benchmarks codes each time I've been doing a larger set of testing.

beetle
05-20-2003, 03:51 PM
Here's why

1) I already have the data as an array
2) Object preparation too verbose and unecessary - would still require hand-holding for my setup (remember - I'm automating this process)
3) Higher learning curve for those who wish to extend my script

I'm not really looking for a solution or wanting to change what I've got, fellas. Just enjoying the discussion :D

HairyTeeth
05-26-2003, 10:18 AM
I have considered your question...i have no result...can you (beetle) show me the way not to do it?

Also: Benny Gooman pulses

beetle
05-26-2003, 04:18 PM
There is no way - not without using apply().
Originally posted by HairyTeeth
Also: Benny Gooman pulses Eh?

HairyTeeth
05-26-2003, 10:12 PM
it was just an aside...jazz.

Also, I've just sussed out custom objects. Looking at the tutorials on the web (which involve Math, cars and real estate), and aside from my own initial endeavours (methods to convert radians to degrees), in practice, what is the value of creating custom objects?

liorean
05-26-2003, 10:45 PM
They are neat and easily readable, allow named arguments and are order indifferent.Personell.add({
name: 'n.n.',
jobtitle: 'Web Designer',
salary: 'ad natura',
age: "won't say"
});For example.