Getting Line Numbers From eval()

When it comes to executing code, eval() is not very good at picking up syntax errors. It’s line number is consistently the point of eval() and not the line in the eval-ed code that contained the problem. Script tags, however, are free of these problems, and report line numbers as parse errors. What results is an alternate technique for eval(), which can catch parse errors in JavaScript code.

Since using eval() usually is indicative of another problem, this variant should be used as a last resort.

No Really, Don’t Use eval

I don’t think it’s possible to be more clear about this. Unless you are writing an in-browser transpiler of some kind or something equally crazy, you shouldn’t need or want eval(). Use of eval() usually implies there are deeper issues to resolve. Additionally, these techniques will not work if a site has enabled Content Security Policy features and disabled script tag usage without a source.

.innerHTML and .text

The first attempt was to set innerHTML to your JavaScript, and then place that node onto the page via appendChild. If you are only concerned with modern non-microsoft browsers, you’d be done at this point.

Internet Explorer won’t execute the JavaScript inside of this script tag, even though the innerHTML property is set. However, it uniquely supports the “text” property, which no other browsers seem to support. When set, scripts in IE will execute once appended to the DOM. A few changes to our above script, and we have a “safe” method. Borrowing from the idea of feature testing for things only IE supports, we’ll actually feature test against this text property, falling back to alternate versions as needed.

Tying it Together

Further optimizations can be used to pre-select the best insertion method. In inject, we wrap the code we want to execute within a function declaration and assignment. This enables us to store the results of the “eval” so that modules can then be executed on demand. The below example is just a simple JSON evaluator as a proof of concept. Like all things eval, you should always be cautious with invoking eval() on items that are not 100% in your control.

While this code definitely makes it possible to do more harm than good (we’re stepping around JSLint/Hint eval checks), the upside is huge when you’re evaluating code and need to understand at what line something is failing on. In the case of a module loading system, having both the upside of eval and the upside of an embedded script tag is a huge win for developers.

This article is from the archives of felocity.com. The original unedited post can be found in the github archives. It has recieved a quick once-over to modernize the content where applicable, but may contain references and links to code that is dead, unloved, or may simply no longer apply to modern web development.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.