如何创建可与 let 和 const 一起使用的 JavaScript REPL?
How to create JavaScript REPL that will work with let and const?
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
,但我不喜欢这个解决方案。
编辑:重复问题的答案只说明为什么 let
和 const
在 eval
中不起作用,但不要不要回答如何使用 let
或 const
进行评估,就像在 Dev Tools 中一样。我的问题是:如何使 eval
与 let
和 const
.
一起工作
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。
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
,但我不喜欢这个解决方案。
编辑:重复问题的答案只说明为什么 let
和 const
在 eval
中不起作用,但不要不要回答如何使用 let
或 const
进行评估,就像在 Dev Tools 中一样。我的问题是:如何使 eval
与 let
和 const
.
var __EVAL = (s) => eval(`void (__EVAL = ${__EVAL}); ${s}`);
__EVAL("const a = 42;"); // undefined
__EVAL("a;"); // 42
它完全符合我的需要。
此代码的来源来自对这个问题的回答:
编辑:
为了将来参考,因为我将删除这段代码,所以我发布了我使用的解决方案:
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。