alternative to eval() in DOM manipulation - javascript

I am converting tutorials for students (2nd language speakers, 9 to 12 yrs old) to access in an offline / intranet context. Hence the websites I would like them to use are unavailable.
I am trying to mimic the 'alter the code' style of tutorials for helping with JavaScript / HTML5 Canvas.
This works :
<canvas id="myCanvas" height="400px" width="400px"></canvas>
<script>
function update(){
eval(document.getElementById('demoScript').value);
}
var ctx = document.getElementById("myCanvas").getContext("2d");
</script>
<textarea id="demoScript">
ctx.fillRect(100,100,50,50);
</textarea>
<input type="button" value="update" onClick="update()">
... but everything I have read says eval() is a bad idea.
I can get the textarea content to pop-up in a div if I want, but I can't get it to pop-up in a script anywhere ... leaving me with just eval().
Options and recommendations for alternatives please ... or this is as good as it gets ?

This is an acceptable use for eval, because at worst a student will lock up their own browser with an infinite loop.

First of all, it's not a "bad idea" to use eval.
Second: anything that replaces eval will have the same "disadvantages" since it executes code. You'll have to execute code to do this. If you don't want to make your own interpreter (which is at least ten times worse and more vulnerable) you'll have to stick with eval or something similar.
Now what is the danger of it? Nothing else but the fact that it executes code. It's like telling someone that a hammer is dangerous because it hits hard - YES, and it's necessary when it gets to nailing something. Of course, a hammer can kill.
So,
Use eval,
...but sanitize the code it gets (= watch out for dangerous expressions, etc).
You can limit a lot of things for the user, like only one instruction per line, only double quotes, etc, to make it more controllable. Anything that's off the limit will be deleted. If no dangerous thing can be pushed thru the input, eval is harmless.

Options and recommendations for alternatives please ... or this is as good as it gets ?
I'd suggest using the Function constructor instead of eval. While in your simple example it may not make much difference, in other cases it may.
This will make the code evaluate in the global scope, so none of your local variables can be touched. It also allows JS engines to more easily optimize the local code. Using eval() can disable optimizations.
So to use the Function constructor, just pass the code to eval as the last argument. Since you have no parameters to define for the new function, it'll be the only argument.
var f = new Function("return " + document.getElementById("demoScript").value);
Then invoke the function.
f();
Notice that I concatenated a return statement into the provided code. This isn't required if you don't care about getting the returned value from the code your invoking, and should be removed if it might interfere with the provided code.
And of course, you can do this all in one line if you're only going to invoke it once.
new Function(document.getElementById("demoScript").value)();

You can get the value string from the textarea, split, validate and run it manually.
For a demonstration like this, where ctx is given, something like this should work
var ctx = document.getElementById("myCanvas").getContext("2d");
function update(){
var val = document.getElementById('demoScript').value,
fn = val.match(/\.(.*?)\(/),
arg = val.match(/\((.*?)\)/);
if (fn && fn.length > 0) {
if (arg && arg.length > 0) {
var args = arg[1].indexOf(',') != -1 ? arg[1].split(',') : [arg[1]];
ctx[fn[1]].apply(ctx, args);
}else{
ctx[fn[1]]();
}
}
}
FIDDLE

You could do
var fn = document.getElementById("demoScript").value;
window[fn]();

Related

Find out where this function has been called?

I want to be able to quickly go through all invocations of a function inside a file or outside. Currently i use search in all files method. But is there a way to see where this method was used.
Optional: Also i'd want to go back in other direction as well. Say there is a method call like this:
makeBread();
Now i want to see what the function do. so somehow jump to its declaration.
Find invocation
Trying to use text search to find invocations may easily betray you. Consider this:
function myFunction() {
console.log("Hello :)");
}
document.getElementById("page-title").addEventListener("click", myFunction);
I think you understand where this is going - if you want to get a list of invocations, best bet is to use console.trace at runtime:
function myFunction() {
console.trace();
console.log("Hello :)");
}
Find what the function does
The function can be overriden at runtime. Dynamic languages cannot be analysed like static ones (C++, Java). You wanna know what the function does? Print it in the console at runtime:
console.log(makeBread.toString());
Find declaration
Again, console.trace will tell you the line for every function it came through. You can also get the stack trace as array - but beware that this slows execution a lot, so don't do it in production.
Conclusion
As I said, you cannot inspect dynamic languages where anything can be anything using any IDE reliably. Most IDEs give good hints though, just conbine them with runtime debuging. Consider debuging running application more fun than looking ad the dead code.
More reading
If you want to make some reguler expressions, this is gonna be handy: http://www.bryanbraun.com/2014/11/27/every-possible-way-to-define-a-javascript-function
The console object: https://developer.mozilla.org/en-US/docs/Web/API/Console
Using stack trace: https://stackoverflow.com/a/635852/607407
Not natively, but with plugins, yes
A popular plugin that has this functionality is SublimeCodeIntel:
SublimeCodeIntel will also allow you to jump around symbol definitions even across files with just a click ..and back.
For Mac OS X:
Jump to definition = Control+Click
Jump to definition = Control+Command+Alt+Up
Go back = Control+Command+Alt+Left
Manual Code Intelligence = Control+Shift+space
For Linux:
Jump to definition = Super+Click
Jump to definition = Control+Super+Alt+Up
Go back = Control+Super+Alt+Left
Manual Code Intelligence = Control+Shift+space
For Windows:
Jump to definition = Alt+Click
Jump to definition = Control+Windows+Alt+Up
Go back = Control+Windows+Alt+Left
Manual Code Intelligence = Control+Shift+space

What is the role of variables (var) in Javascript

I am currently learning JavaScript and I am wondering what is the role of the variables (var).
In the example bellow, on the last two lines we first define a variable "monCompte" in which we call "john.demandeCaissier(1234)". Then we use console.log(monCompte) to print the result on the screen. What I don't understand is why do we first need to define the variable "monCompte" to call "john.demandeCaissier(1234)". Why can't we just do something such as:
console.log(john.demandeCaissier(1234));
Example
function Personne(prenom,nom,age) {
this.prenom = prenom;
this.nom = nom;
this.age = age;
var compteEnBanque = 7500;
this.demandeCaissier = function(mdp) {
if (mdp == 1234) {
return compteEnBanque;
}
else {
return "Mot de passe faux.";
}
};
}
var john = new Personne('John','Smith',30);
var monCompte = john.demandeCaissier(1234);
console.log(monCompte);
Thank you for you answers.
Yes, you can inline your function call and avoid the need for a variable. However, if an error occurs on that line, it becomes harder to debug:
var monCompte = john.demandeCaissier(1234);
console.log(monCompte);
vs
console.log(john.demandeCaissier(1234));
in the second example, there are several different modes of failure that would not be apparent in a debugging session. When split over two lines, some of those failures become easier to track down.
Second, if you wanted to reuse the value returned by john.demandeCaissier(1234) (the author might have shown this), then a variable becomes very useful indeed.
In my opinion, it's a worthy pursuit to perform only a single operation per line. Fluent-style advocates might disagree here, but it really does make debugging considerably easier.
You could definitely do that, but in more complex programs you will need to store variables for several reasons:
Shortening Long Expressions
Imagine if you saw this code somewhere:
console.log((parseInt(parseFloat(lev_c + end_lev_c)) - parseInt(parseFloat(lev_c + start_lev_c)) + 1));
BTW I got that from here
Wouldn't it be so much simpler just to split that expression up into different variables?
Storing Data
Let's say that you take some input from the user. How would you refer to it later? You cannot use a literal value because you don't know what the user entered, so do you just call the input function again? No, because then it would take the input a second time. What you do is you store the input from the user in a variable and refer to it later on in the code. That way, you can retrieve the value at any time in the program.
If you are a beginner, you might not see any use for variables, but when you start writing larger programs you will start to use variables literally in almost every line of code.
Variables exist to store data. They're useful because instead of invoking an operation over and over again, which is criminally inefficient, they allow you to invoke an operation once, and then use that result where necessary.
And that's for all languages, not just JavaScript.
Variables are structures that store some value (or values). They're only that and you could probably do all your code (or the majority of it) without them.
They help you organize and add some readability to your code. Example:
alert(sumNumbers(askNumber()+askNumber()));
takes a lot more effort to read/understand then this:
var firstNumber = askNumber();
var secondNumber = askNumber();
var total = sumNumbers(firstNumber + secondNumber);
alert(total);
Sure it's longer but it's more readable. Of course you don't have to use var for everything, in this case I could just hide the total.
Another common use for variables is "caching" a value.
If you had a function that sums like 1 million values, if you keep calling it for everything, your code would always have to do all that hard work.
On the other hand, if you store it on a variable the first time you call it, every other time you need that value again, you could just use the variable, since its a "copy" of that calculation and the result is already there.

Scenarios for Re-using Variables within the Same JavaScript Function: Always a No No?

I've just finished writing a script for parsing csv data. Having recently installed JShint, it's been badgering me about the re-use of variables. I've been using JS a fair bit lately, but I come from a python background where it's normal to reuse variables. I'm wondering what issues there are with reusing variables in the following two examples:
Loop with a Switch
The following loop steps through the rows on a csv file, and when it passes a certain value in a row, it switches variable "currentSwitch" from false to true. After currentSwitch is tripped, the loop starts to push stuff to an array.
for (f=0; f < data.length; f++){
if (data[f][0] === code){
if (currentSwitch === true){
dataListByCode.push(data[f]);
}
}
else if ((data[f][0]).slice(0,4) === "UNIN"){
var currentSwitch = true;
}
}
Processing Data with Broken Out Functions
I've got a few functions for processing data that it makes sense to keep separate. In the following code, I process with one function, then I process with another.
var dataListByCode = addDivideData(dataListByCode);
var dataListByCode = addBeforeEntriesArray(dataListByCode, invNumber, matterNumber, client, workType);
Can anyone tell me if this is not in line with best practice? Is there anything that could go wrong with either of these (or scenarios like them)?
You don't need to redeclare currentSwtich
var currentSwitch = true;
In fact it really doesn't make any sense to redeclare this variable in the middle of the loop and in most cases it's almost certainly not what you actually want.
Just initialize/declare it once at the beginning of your loop
var currentSwtich;
// or
var currentSwitch = false;
and drop the var when you set it to true:
currentSwitch = true;
Basically what you are doing is creating a brand new variable with the same name as the old one, and throwing away the old one. This isn't really what you want normally.
There is no analogous concept in python because python doesn't require you to declare variables.
The major problem with reusing variables is that:
a.) in bigger code blocks it can get very confusing, especially if you added/removed code ~20 times, and kept reusing same ~5 variables for multiple things
b.) any programmer that knows nothing about code(read: you after couple months/years) will have a much more difficult time grasping the code.
The lower function snippet can be expressed as:
var dataListByCode = addBeforeEntriesArray(addDivideData(dataListByCode), invNumber, matterNumber, client, workType);
which is not that problematic. The breaking up of functions is useless in this case, and if you have many inline function chains that is usually sign that you need to rethink the object/function design.

JSLint "eval is evil." alternatives

I am have some JavaScript functions that run on both the client (browser) and the server (within a Java Rhino context). These are small functions - basically little validators that are well defined and don't rely upon globals or closures - self-contained and portable.
Here's an example:
function validPhoneFormat(fullObject, value, params, property) {
var phonePattern = /^\+?([0-9\- \(\)])*$/;
if (value && value.length && !phonePattern.test(value))
return [ {"policyRequirement": "VALID_PHONE_FORMAT"}];
else
return [];
}
To keep things DRY, my server code gets a handle on each of these functions and calls toString() on them, returning them to the browser as part of a JSON object. Something like this:
{ "name" : "phoneNumber",
"policies" : [
{ "policyFunction" : "\nfunction validPhoneFormat(fullObject, value, params, property) {\n var phonePattern = /^\\+?([0-9\\- \\(\\)])*$/;\n if (value && value.length && !phonePattern.test(value)) {\n return [{\"policyRequirement\":\"VALID_PHONE_FORMAT\"}];\n } else {\n return [];\n }\n}\n"
}
]
}
My browser JS code then takes this response and creates an instance of this function in that context, like so:
eval("var policyFunction = " + this.policies[j].policyFunction);
policyFailures = policyFunction.call(this, form2js(this.input.closest("form")[0]), this.input.val(), params, this.property.name));
This all works very well. However, I then run this code through JSLint, and I get back this message:
[ERROR] ValidatorsManager.js:142:37:eval is evil.
I appreciate that often, eval can be dangerous. However, I have no idea how else I could implement such a mechanism without using it. Is there any way I can do this and also pass through the JSLint validator?
I wouldn't worry about it since you are only passing these function strings from the server to the client, and are thus in control of what will be evaluated.
On the other hand, if you were going the other direction and doing the evals of client-passed code on the server, that would be an entirely different story...
Update:
As disabling the validation option in your comment may cause you to miss future errors, I would instead suggest passing the function name rather than the entire function and have the function library mirrored on the server and client. Thus, to call the function, you'd use the following code:
var policyFunction = YourLibraryName[this.policies[j].policyFunctionName];
var policyArguments = this.policies[j].policyArguments;
policyFunction.apply(this, policyArguments);
Update 2:
I was able to validate the following code with JSLint successfully, which essentially allows you to "turn off" validation for the vast minority of cases where eval is appropriate. At the same time, JSLint still validates normal eval calls, and all uses of this method should throw up flags for future developers to avoid using it/refactor it out where possible/as time allows.
var EVAL_IS_BAD__AVOID_THIS = eval;
EVAL_IS_BAD__AVOID_THIS(<yourString>);
Dont encode a function as a string in JSON. JSON is for content, which you are confounding with behavior.
Instead, I suppose you could return JS files instead, which allow real functions:
{ name : "phoneNumber",
policies : [
{ policyFunction : function() {
whateverYouNeed('here');
}
}
]
}
But while that solves the technical issue, it's still not a great idea.
The real solution here is to move your logic out of your content entirely. Import a JS file full of little validation functions and call them as needed based on a dataType property in your JSON or something. If this functions are as small and portable as you say, this should be trivial to accomplish.
Getting your data all tangled up with your code usually leads to pain. You should statically include your JS, then dynamically request/import/query for your JSON data to run through your statically included code.
I would avoid using eval in all situations. There's no reason you can't code around it. Instead of sending code to the client, just keep it hosted on the server in one contained script file.
If that's not doable, you can also have a dynamically generated javascript file then pass in the necessary parameters via the response, and then dynamically load the script on the client side. There's really no reason to use eval.
Hope that helps.
You can use
setInterval("code to be evaluated", 0);
Internally, if you pass setInterval a string it performs a function similar to eval().
However, I wouldn't worry about it. If you KNOW eval() is evil, and take appropriate precautions, it's not really a problem. Eval is similar to GoTo; you just have to be careful and aware of what you're doing to use them properly.
With very little parsing you could have had it like so:
var body = this.policies[j].policyFunction.substr;
body = body.substr(body.indexOf("(") + 1);
var arglist = body.substr(1, body.indexOf(")"));
body = body.substr(arglist.length + 1);
var policyFunction = new Function(arglist, body);
Which would provide a bit of validation, avoid the literal use of eval and work synchronously with the code. But it is surely eval in disguise, and it is prone to XSS attack. If the malevolent person can get their code loaded and evaluated this way - it will not save you. So, really, just don't do it. Add a <script> tag with the proper URL and that would be certainly safer. Well, you know, better safe then sorry.
PS. My apologises if the code above doesn't work, it only shows the intent, I've not tested it, and if I made a mistake at counting parenthesis or some such - well, you should get the idea, I'm not advertising it by any means.
DRY is definitely something I agree with, however there is a point where copy+pasting is more efficient and easy to maintain than referencing the same piece of code.
The code you're saving yourself from writing seems to be equivalent to a clean interface, and simple boiler plate. If the same code is being used on both the server and the client, you could simply pass around the common pieces of the function, rather than the whole function.
Payload:
{
"name": "phoneNumber",
"type": "regexCheck",
"checkData": "/^\\+?([0-9\\- \\(\\)])*$/"
}
if(payload.type === "regexCheck"){
const result = validPhoneFormat(fullObject, value, payload.checkData)
}
function validPhoneFormat(fullObject, value, regexPattern) {
if (value && value.length && !regexPattern.test(value))
return [ {"policyRequirement": "VALID_PHONE_FORMAT"}];
else
return [];
}
This would give you the ability to update the regex from a single location. If the interface changes it does need to be updated in 2 places, but I wouldn't consider that a bad thing. If the client is running code, why hide the structure?
If you really, really want to keep both the object structure and the patterns in one place - extract it to a single API. Have a "ValidatePhoneViaRegex" api endpoint which is called by all places you'd be passing this serialized function to.
If all of this seems like too much effort, set jslint to ignore your piece of code:
"In JSHint 1.0.0 and above you have the ability to ignore any warning with a special option syntax. The identifier of this warning is W061. This means you can tell JSHint to not issue this warning with the /*jshint -W061 */ directive.
In ESLint the rule that generates this warning is named no-eval. You can disable it by setting it to 0, or enable it by setting it to 1."
https://github.com/jamesallardice/jslint-error-explanations/blob/master/message-articles/eval.md
I would prefer to see copy+pasted code, a common api, or receiving parameters and copy+pasted boiler plate than magical functions passed in from the server to be executed.
What happens if you get a cross-browser compatibility error with one of these shared functions?
Well, the first thing to bear in mind is that jsLint does make the point that "it will hurt your feelings". It's designed to point out where you're not following best practices -- but code that isn't perfect can still work just fine; there's no compulsion upon you to follow jsLint's advice.
Having said that, eval is evil, and in virtually all cases there is always a way around using it.
In this case, you could use a library such as require.js, yepnope.js or some other library that is designed to load a script separately. This would allow you to include the javascript functions you need dynamically but without having to eval() them.
There are probably several other solutions as well, but that was the first one that came to my mind.
Hope that helps.

jQuery limit plugin concerns

This question is in reference to this jQuery limit plugin. Here's the source:
(function($){
$.fn.extend({
limit: function(limit,element) {
var interval, f;
var self = $(this);
$(this).focus(function(){
interval = window.setInterval(substring,100);
});
$(this).blur(function(){
clearInterval(interval);
substring();
});
substringFunction = "function substring(){ var val = $(self).val();var length = val.length;if(length > limit){$(self).val($(self).val().substring(0,limit));}";
if(typeof element != 'undefined')
substringFunction += "if($(element).html() != limit-length){$(element).html((limit-length<=0)?'0':limit-length);}"
substringFunction += "}";
eval(substringFunction);
substring();
}
});
})(jQuery);
Now I may just be nitpicking here... but maybe I'm missing something. Here are my questions/concerns:
1) What is the purpose of creating the substring function in a string and then eval'ing it? Looking through, it seems like the extension would work perfectly fine if the function was initialized normally.
2) I don't like that it uses a setInterval to execute the substring function. Wouldn't a keypress or similar event be the better and more logical way to do this? Also, I believe this to be the cause of (or at least enabling) the 'flickering text' bug that is referenced in the v1.2 change log (No, it isn't fixed).
3) Why is the variable f initialized? It is never used or referenced.
4) Also, this isn't a chainable method, and as a jQuery extension, it should be. I'm not too familiar with writing jQuery extensions, but this can be accomplished by return this; at the end of the method, correct?
It seems like this is just a case of poor programming, but I'd like to get an outside opinion.
1) I agree. Looks like he doesn't understand closures to me.
2) It's hard to predict exactly which events might change the contents of the textbox. Keypresses are obvious, but maybe mouse events could also do it. It could also be updated by other Javascript functions.
3) I have a couple of guesses: a) He was using it to hold the callback function when he was trying to get the closure to work, and didn't remove the declaration when he switched to the eval kludge; b) it was supposed to hold the substring function string, but he made a mistake and called it substringFunction when he assigned it (notice that he forgot the var declaration there).
4) True.
Just because someone posts their code to a web site doesn't mean they're an expert.

Categories

Resources