This question already has an answer here:
-
What are the Alternatives to eval in JavaScript?
8 answers
Mozilla's Content Security Policy disallows the use of javascript eval function as well as inline scripts. They claim that all instances of eval can be replaced by another (hopefully safer) function. I agree in most scenarios, Javascript eval can be replaced, but I'm not sure whether the replacement is possible for every case.
My question is twofold:
- Is there a generic way to replace every javascript eval function? (doesn't have to be safe)
- Is there a case where the Javascript eval cannot be replaced?
The most common uses which can be substituted are the following ones. I would certainly use these first.
Accessing dynamic properties
Do use: obj[keyAsVariable]
Don't use eval('obj.' + keyAsVariable)
Parsing JSON
Do use JSON.parse(data)
Don't use eval('(' + data + ')')
Calculating user input
Do use a certain library
Don't use eval(input)
If really necessary, you can also send the script to a server which simply echoes it back, and you can request it as a script tag. It won't use eval
but still execute it. It isn't safe as it's sent twice over the Internet.
var s = document.createElement('script')
s.src = 'request_script?data=' + data;
document.getElementsByTagName('head')[0].appendChild(s);
request_script
could be a file implemented in PHP, like the following. Again, it's bad practice but is a generic way of circumventing eval
.
<?
echo $_GET['data'];
?>
You could say that this also automatically answers your second question with 'no'.
You could wrap the java script within a function call similar to JSONP and then dynamically create a script tag to load that.
Load as script using a Blob
Instead of using eval
you can also use a Blob
and load the code as if it was an external js
file:
To ensure that functions or variables that are inside the code that you are loading are available you need to use a callback
method that will be triggered onload
event.
var code = "console.log('hello world');";
// With eval:
eval(code);
// With a blob:
var blob = new Blob([code], {type: 'text/javascript'});
var urlCreator = window.URL || window.webkitURL;
var url = urlCreator.createObjectURL( blob );
function loadScript(url, callback)
{
// Add a the script tag to the head
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
// Bind the callback (depends on browser compatibility).
script.onreadystatechange = callback;
script.onload = callback;
// Load the script
head.appendChild(script);
}
// Any variables or methods inside the code will be on callback.
loadScript(url, callback);
Note Be aware that the danger for code injection is similar to eval.