如何创建可与 let 和 const 一起使用的 JavaScript REPL?

How to create JavaScript REPL that will work with let and const?

我有 simple JavScript REPL:

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));
         }
     }
 }

但它不适用于 let 或 const:

js> let x = 10
js> x
ReferenceError: x is not defined
js> 

是否有破解方法可以使这项工作正常进行?我不知道 Google Chrome Dev Tools 如何让它工作。阅读代码可能需要很长时间。只是想问一下,我可能会花很多时间阅读它的代码。

我知道我可以在评估之前将 let 替换为 var,但我不喜欢这个解决方案。

编辑:重复问题的答案只说明为什么 letconsteval 中不起作用,但不要不要回答如何使用 letconst 进行评估,就像在 Dev Tools 中一样。我的问题是:如何使 evalletconst.

一起工作

Someone posted on Reddit 此代码:

var __EVAL = (s) => eval(`void (__EVAL = ${__EVAL}); ${s}`);

__EVAL("const a = 42;"); // undefined
__EVAL("a;"); // 42

它完全符合我的需要。

此代码的来源来自对这个问题的回答:(正如 OP 在 Reddit 上所指出的)。

编辑:

为了将来参考,因为我将删除这段代码,所以我发布了我使用的解决方案:

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

使用 vm 节点模块(browserify 的一部分)和使用 browserify 转换的 node-falafel。