Tengo un simple REPL de JavScript :
function(command) { if (command !== '') { try { var result = window.eval(command); if (result) { if (result instanceof $.fn.init) { this.echo(`#<jQuery>`); } else if (typeof result === 'object') { var name = result.constructor.name; if (name) { this.echo(`#<${name}>`); } else { this.echo(result.toString()); } } else { this.echo(new String(result)); } } } catch(e) { this.error(new String(e)); } } }Pero no funciona con let o const:
js> let x = 10 js> x ReferenceError: x is not defined js>¿Hay algún truco que haga que esto funcione? No tengo idea de cómo Google Chrome Dev Tools lo hace funcionar. Probablemente llevará mucho tiempo leer el código. Solo quiero preguntar antes de que posiblemente pase mucho tiempo leyendo su código.
Sé que puedo reemplazar let con var antes de la evaluación, pero no me gusta esta solución.
EDITAR : las respuestas a la pregunta duplicada solo muestran por qué let y const no funcionan en eval , pero no responden cómo hacer que eval funcione con let o const , como en Dev Tools. Mi pregunta es: cómo hacer que eval funcione con let y const .
Alguien publicó en Reddit este código:
var __EVAL = (s) => eval(`void (__EVAL = ${__EVAL}); ${s}`); __EVAL("const a = 42;"); // undefined __EVAL("a;"); // 42Y hace exactamente lo que necesito.
La fuente de este código provino de la respuesta a esta pregunta: evaluación de preservación del contexto (como lo señaló el OP en Reddit).
EDITAR :
Para referencia futura, porque eliminaré este código, publico la solución que estaba usando:
const context = { __$$__: {}, ...globals(), $, console: { log(...args) { console.log(...args); term.echo(args.map(repr).join(' ')); } } }; function unset(context, name) { delete context[name]; } function exec(code, ctx = context) { ctx = {...ctx}; code = patch(code, ctx) return vm.runInNewContext(code, ctx); } function is_scoped(name, context) { return name in context.__$$__; } function patch(code, context) { let patching = []; let result = falafel(code, function(node) { if (node.type == 'VariableDeclaration') { node.declarations.forEach(declaration => { const name = declaration.id.name; if (is_scoped(name, context)) { unset(context, name); } patching.push(`__$$__.${name} = ${name}`); }); } else if (node.type === 'Identifier' && is_scoped(node.name, context) && node.parent.type !== 'VariableDeclarator') { const name = node.name; node.update(`__$$__.${name}`); } }); result = result.toString(); if (patching.length) { result += ';' + patching.join(';'); } return result; }Usando el módulo de nodo vm (parte de browserify) y node-falafel convertido usando browserify también.