I am dynamically creating a function on a Foo1
instance named test
. I am creating this function using eval
. I would expect that this function would have access to the Foo2
class, however I am getting a ReferenceError: Foo2 is not defined
.
I have opened up an issue with Babel
about this and can be be found here
If you would like to run the example code yourself, download it from here and follow the instructions in the README.MD
to reproduce.
To run:
npm install npm run start naviage to localhost:8080
Here is the directory structure for my Minimal, Complete, and Verifiable example in my environment:
root
- src
- Foo1.js
- Foo2.js
- .babelrc
- app.js
- package.json
Foo1.js
import Foo2 from './Foo2.js';
export default class Foo1 {
constructor() {
// Isolate the impact of eval within makeFunction
let makeFunction = text => {
return eval("(function() { " + text + "})");
};
this.test = makeFunction('let foo2 = new Foo2(); foo2.test();');
}
}
Foo2.js
export default class Foo2 {
test() {
console.log('i\'m working!');
}
}
.babelrc
{
"presets": ["es2015"]
}
app.js
import express from 'express';
import http from 'http';
import Foo1 from './src/Foo1.js';
const app = express();
const server = http.createServer(app);
app.get('/', (req, res) => {
let test = new Foo1();
test.test();
res.end('bye');
});
server.listen(8080);
package.json
{
"name": "test",
"scripts": {
"start": "./node_modules/babel-cli/bin/babel-node.js ./app.js"
},
"dependencies": {
"http": "*",
"express": "*",
"babel-cli": "^6.7.7",
"babel-core": "^6.7.7",
"babel-polyfill": "^6.3.14",
"babel-preset-es2015": "^6.6.0"
}
}
Now, If I change the Foo2.js
class to the previous version of javascript everything works like a charm:
function Foo2() { }
Foo2.prototype.test = function() {
console.log('i\'m working!');
};
module.exports = Foo2;
The eval() function evaluates JavaScript code represented as a string and returns its completion value. The source is parsed as a script.
Malicious code : invoking eval can crash a computer. For example: if you use eval server-side and a mischievous user decides to use an infinite loop as their username. Terribly slow : the JavaScript language is designed to use the full gamut of JavaScript types (numbers, functions, objects, etc)… Not just strings!
$$eval() method. This method runs Array. from(document. querySelectorAll(selector)) within the page and passes the result as the first argument to the pageFunction .
An alternative to eval is Function() . Just like eval() , Function() takes some expression as a string for execution, except, rather than outputting the result directly, it returns an anonymous function to you that you can call. `Function() is a faster and more secure alternative to eval().
It looks like your code is being encapsulated in a module. Top-level declarations in modules are not globals, but as you've discovered, functions created with new Function
do not close over the context in which they're created; they're created as though they were at global scope.
As you've indicated, new Function
isn't ideal as it provides for evaluation of arbitrary code, but if you control and can trust the code you're evaluating, that's not necessarily a problem. The presence of new Function
also pretty much blows up the JavaScript engine's ability to optimize the code where it appears (since it cannot know what's in the function text), so best to keep these fairly isolated if you can.
Since new Function
already has both of those problems, we can go ahead and use eval
, which shares them: eval
works in the current scope, rather than global scope.
eval
example:
// Scoping function to fake the effect of module scope
(function() {
let foo = "bar";
let algorithm = "console.log(foo);";
let fn = makeFunction(algorithm);
fn();
// Isolate the impact of eval within makeFunction
function makeFunction(text) {
return eval("(function() { " + text + "})");
}
})();
Let me reiterate the issues with using eval
, just to be really clear:
It's important that you only eval
code you can trust
Using eval
in an execution context basically makes it impossible for the JavaScript engine to optimize the code in that context, so keep it isolated to small functions if you can to contain the issue
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With