Javascript `eval ()` scope in ES6

I dynamically create a function in the instance Foo1 named test . I create this function using eval . I would expect that this feature will have access to the class Foo2 , but I get ReferenceError: Foo2 is not defined .

I opened with the problem of Babel about it can be found here

If you want to run the sample code yourself, download it from here and follow the instructions in README.MD to play.

For start:

  npm install
 npm run start
 naviage to localhost: 8080

Here is the directory structure for my minimum, complete and verifiable examples 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();'); } } {" + text + "})"); 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();'); } } new Foo2 (); foo2.test ();'); 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!'); } } '!); export default class Foo2 { test() { console.log('i\'m working!'); } } 

.babelrc

 { "presets": ["es2015"] } ] { "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); , res) => { 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" } } 6.7.7", { "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" } } 6.7.7", { "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" } } 6.3.14", { "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" } } "^ 6.6.0" { "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 changed the class Foo2.js to the previous version of javascript, it works like a charm:

 function Foo2() { } Foo2.prototype.test = function() { console.log('i\'m working!'); }; module.exports = Foo2; '!); function Foo2() { } Foo2.prototype.test = function() { console.log('i\'m working!'); }; module.exports = Foo2; 
+7
source share
2 answers

It looks like your code is encapsulated into a module. Ads in the top-level modules are not global, but as you have discovered the function created with new Function , do not close the context in which they are created; they are created as if they were on a global scale.

As you pointed out, new Function is not ideal because it provides an assessment of arbitrary code, but if you are in control and can trust code that you assess, is not necessarily a problem. The presence of new Function is also largely entails the ability of JavaScript-engine optimize the code where it appears (because he can not know that the text of the function), so it is best to keep them isolated enough, if you can.

Since the new Function already has both of these problems, we can go ahead and use eval , which separates them: eval runs in the current scope, not in the global scope.

eval example:

 // Scoping function so we know for sure we're not creating globals (function() { var foo = "bar"; var algorithm = "console.log(foo);"; var f = makeFunction(algorithm); f(); // Isolate the impact of eval within makeFunction function makeFunction(text) { return eval("(function() { " + text + "})"); } })(); {" + text + "})"); // Scoping function so we know for sure we're not creating globals (function() { var foo = "bar"; var algorithm = "console.log(foo);"; var f = makeFunction(algorithm); f(); // Isolate the impact of eval within makeFunction function makeFunction(text) { return eval("(function() { " + text + "})"); } })(); 
Run codeHide result

Let me repeat that the problem with the use of eval , to be really clear

  • It is important that you only code eval can trust

  • The use of eval in the context of the implementation basically makes it impossible to JavaScript engine optimized code in this context, so keep it isolated from small functions if you can keep the problem.

+6
source

The reason that this does not work is that you are using the babel to convert their code, which makes the import Foo2 and all references to Foo2 in access to some properties of an object. But he can not change your eval'd-code, as he is known only at run time, rather than in assembly time, so your Foo2 remains unchanged and valid.

0
source

All Articles