2016-07-29 7 views
5

Ich erstelle dynamisch eine Funktion auf einer Foo1 Instanz namens test. Ich erstelle diese Funktion mit eval. Ich würde erwarten, dass diese Funktion Zugriff auf die Foo2 Klasse hätte, aber ich bekomme eine ReferenceError: Foo2 is not defined.Javascript `eval()` Bereich in ES6

Ich habe ein Problem mit Babel darüber eröffnet und here

gefunden werden kann, wenn man sich den Beispielcode ausführen möchten, laden Sie es von here und folgen Sie den Anweisungen in der README.MD zu reproduzieren.

auszuführen:

 
npm install 
npm run start 
naviage to localhost:8080 

Hier ist die Verzeichnisstruktur für mein Minimal, Complete, und prüfbare Beispiel in meiner Umgebung:

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" 
    } 
} 

Jetzt, Wenn ich die Foo2.js Klasse auf die vorherige Version von JavaScript funktioniert alles ändern, wie ein Charme:

function Foo2() { } 

Foo2.prototype.test = function() { 
    console.log('i\'m working!'); 
}; 

module.exports = Foo2; 
+0

Okay I Ich bearbeite die Frage gerade – frankgreco

+2

Hervorragende Anstrengung auf dem MCVE, BTW. –

Antwort

4

Es sieht so aus, als wäre Ihr Code in einem Modul gekapselt. Top-Level-Deklarationen in Modulen sind nicht Globals, aber wie Sie festgestellt haben, schließen mit new Function erstellte Funktionen nicht über den Kontext, in dem sie erstellt werden; Sie werden so erstellt, als wären sie auf globaler Ebene.

Wie Sie angegeben haben, ist new Function nicht ideal, da es für die Auswertung von beliebigem Code liefert, aber wenn Sie Kontrolle und den Code vertrauen können Sie bewerten, das ist nicht unbedingt ein Problem. Das Vorhandensein von new Function lässt auch die Fähigkeit der JavaScript-Engine, den Code dort zu optimieren, wo er auftaucht (da er nicht wissen kann, was in dem Funktionstext ist) ziemlich explodieren, also sollten Sie diese möglichst isoliert halten, wenn Sie können.

Da new Function bereits beide dieser Probleme hat, können wir voran gehen und eval verwenden, die sie teilt: eval funktioniert im aktuellen Bereich, anstatt globalen Geltungsbereich.

eval Beispiel:

// 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 + "})"); 
 
    } 
 
})();

Lassen Sie mich die Fragen wiederholen, mit eval verwenden, um nur wirklich klar zu sein

  • Es ist importantt, dass Sie nur eval Code können Sie vertrauen

  • Mit eval in einem Ausführungskontext im Grunde macht es unmöglich, den JavaScript-Engine den Code in diesem Zusammenhang zu optimieren, so hält sie kleine Funktionen getrennt, wenn Sie können, das Problem enthalten

+0

Ja ich benutze ES6 Klassen hier und importiere andere ES6 Klassen über Module. Wie würde ich dann meinen Funktionen, die mit 'new Function' erstellt wurden, denselben Umfang geben, als ob ich die Funktion tatsächlich eingegeben hätte? – frankgreco

+0

@Frank: Die hässliche Antwort ist 'eval'. :-) –

+0

Da Sie möchten, Eval zu "Make this a function" anstatt nur "Do this", denke ich, dass für jede Funktion würden Sie es in "" function() {} " – Katana314