Hoe maak je een JavaScript-interpreter in JavaScript aan met behulp van eval?

Het zou eenvoudig moeten zijn om JavaScript-intepreter in JavaScript te maken met behulp van eval . Ik heb dit (met behulp van de jQuery-terminal):

term = $('#term_demo').terminal(function(command, term) {
    if (command !== '') {
        var result = window.eval("(" + command + ")");
        if (result !== undefined) {
            term.echo(String(result));
        }
    } else {
       term.echo('');
    }
}, {
    greetings: 'Javascript Interpreter',
    name: 'js_demo',
    height: 200,
    prompt: 'js> '
});

Demo

but it don't work when I execute function foo() { ... } the foo is not defined I need to use foo = function() { ... }. eval act like executed within (function() { })(). Can it be there more complicated code that will not work too?

Is het mogelijk om een ​​JavaScript-interpreter te maken met behulp van eenvoudige code zonder gebruik van de js.js , die zal werkt hetzelfde als de browserconsole?

2
@RobW Met eenvoudig bedoel ik de tolkfunctie (8 regel code en deze kan 2 hebben), dit werkt niet functie foo (x) {return x + x; } en foo (10)
toegevoegd de auteur jcubic, de bron
@Alex Omdat js.js 594KB is en JS al interpreter heeft, is het call eval en het heeft 4b (nog een paar als ik het daadwerkelijk wil gebruiken in de code).
toegevoegd de auteur jcubic, de bron
jQuery-terminal ziet er niet echt "eenvoudig" uit. Wat is je doel en waar zit je vast?
toegevoegd de auteur Rob W, de bron
Waarom wil je js.js niet gebruiken?
toegevoegd de auteur madfriend, de bron

2 antwoord

Ik heb een bookmarklet gemaakt met een soort REPL op een pagina, ontworpen voor de vijf belangrijkste browsers (Chrome 1+, IE 6+, Firefox 1+, Safari 3+, Opera 9+ Kan me de herinnering niet herinneren exacte versie ).
De kerncomponent, die de code evalueert, wordt hieronder gepost, enigszins gewijzigd + geannoteerd.

/**
 * Evaluates some code in the global scope.
 * @param String code: Code to eval
 * @return Stringified result, prefixed with 'E:' if error.
 */
function globalEval(/*string*/ code) {
    var win = window, r, raw;
    try {
        if (win.execScript) {//eval in IE sucks, so use execScript instead
            r = win.$_$_$globalEval$_$_$ = {c:code};
            win.execScript('try{$_$_$globalEval$_$_$.r=eval($_$_$globalEval$_$_$.c);}catch(e){$_$_$globalEval$_$_$.e=e}');
           ///*Optional clean-up:*/ delete win.$_$_$globalEval$_$_$;
            if (r.e) throw r.e;//Error
            raw = r.r;
        } else {
            raw = win.eval(code);
        }
        r = '' + raw;//Stringify in the try-block
                     //It is possible that an error is thrown
                     //for example, for the following code: ({toString:1})
    } catch(err) {
        r = (err + '');//Convert error to string
       //IE: If found, "[object" will be at index zero, which is falsy
        if (!r.indexOf('[object')) r = err.message;
       //r = 
        r = 'E:' + (raw=r);
    } finally {
       //raw = unmodified result (or Error instance)
       //FOR THIS EXAMPLE, raw is not used, and string r is returned
        return /*string*/ r;
    }
}

Ik heb de functionaliteit geïmplementeerd in een vorm die verschillende besturingselementen bevat, waaronder een tekstveld voor invoer + uitvoer.

Opmerking: de code wordt geëvalueerd in de globale context. En zo zullen alle variabelen in code worden gelekt naar de globale scope. Voor een tolk kunt u een iframe gebruiken om een ​​nieuw bereik te maken (en de var win in mijn functie aan te passen).

var win = frames['name_of_frame'], ...//or
var win = frame_DOM_element.contentWindow, ...
2
toegevoegd
Ik geef de voorkeur aan een wereldwijd bereik, omdat ik een manier wil geven om met de pagina om te gaan. Ik dacht dat ik het commando tussen haakjes moest zetten, maar het lijkt erop dat ik het niet doe. Bedankt.
toegevoegd de auteur jcubic, de bron
+1 - Leuke functie.
toegevoegd de auteur Brandon Boone, de bron

De haakjes die u rond uw binnenkomende opdracht toevoegt, produceert een illegale syntaxis. U moet het in plaats daarvan inpakken met een anonieme, zelfuitvoerende functie .

Example: http://jsfiddle.net/bW6Fv/1/

var command = "function foo(x){return x+x;} alert(foo(10));";

window.eval("!function(){" + command + "}()");​

BEWERK

Als u wilt dat uw geëvalueerde scripts globaal beschikbaar zijn, moet u ze onverpakt laten of expliciet waarden toewijzen aan het globale vensterobject.

Example: http://jsfiddle.net/bW6Fv/2/

var command = "window.foo = function(x){return x+x;}; alert(foo(10));";

window.eval("!function(){ " + command + "}();");
window.eval("alert(foo(20));");

command = "function bar(x){return x/2;}; alert(bar(10));";

window.eval(command);
window.eval("alert(bar(20));");
0
toegevoegd
Bedankt, ik gebruik het in één code, maar hoe zit het met staat tussen oproepen eval ("(functie() {functie foo (x) {return x + x;}}) ()" en eval ("(function() {alert (foo (10));}" verschillende context foo is undefined, hoe kan ik hiermee omgaan?
toegevoegd de auteur jcubic, de bron
@jcubic In uw eerste code wordt functie foo lokaal gemaakt. Je moet veel hacken als je die JavaScript -functie wilt wijzigen.
toegevoegd de auteur Rob W, de bron