我正在名为test
的Foo1
实例上动态创建一个函数。我正在使用eval
创建此函数。我希望这个函数可以访问Foo2
类,但我得到的是ReferenceError: Foo2 is not defined
。
我已经向Babel
公开了一个关于这方面的问题,可以在这里找到
如果您想自己运行示例代码,请从这里下载,并按照README.MD
中的说明进行复制。
要运行:
npm安装npm运行启动导航到localhost:8080
以下是我的环境中的最小、完整和可验证示例的目录结构:
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);
软件包.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"
}
}
现在,如果我将Foo2.js
类更改为以前版本的javascript,那么一切都像一个魅力:
function Foo2() { }
Foo2.prototype.test = function() {
console.log('i'm working!');
};
module.exports = Foo2;
看起来您的代码被封装在一个模块中。模块中的顶级声明是而不是全局,但正如您所发现的,使用new Function
创建的函数不会在创建它们的上下文中关闭;它们是在全球范围内创建的。
正如您所指出的,new Function
并不理想,因为它提供了对任意代码的评估,但如果您控制并可以信任您正在评估的代码,那就不一定是问题。new Function
的存在也在很大程度上破坏了JavaScript引擎优化代码出现位置的能力(因为它不知道函数文本中有什么),所以如果可以的话,最好将这些代码隔离开来。
由于new Function
已经存在这两个问题,我们可以继续使用eval
,它共享这些问题:eval
在当前范围内工作,而不是在全局范围内工作。
eval
示例:
// Scoping function to fake the effect of module scope
(function() {
let foo = "bar";
let algorithm = "console.log(foo);";
let fn = makeFunction(algorithm);
fn();
// Isolate the impact of eval within makeFunction
function makeFunction(text) {
return eval("(function() { " + text + "})");
}
})();
让我重申使用eval
的问题,只是为了非常清楚:
-
重要的是,您只能信任的
eval
代码 -
在执行上下文中使用
eval
基本上使JavaScript引擎无法优化该上下文中的代码,因此,如果可以的话,请将其与小函数隔离,以包含问题
这不起作用的原因是您使用babel来转换代码,这会将import Foo2
和对Foo2
的所有引用更改为一些对象属性访问。但它不能更改您的eval代码,因为这只在运行时才知道,而在构建时不知道,所以您的Foo2保持不变且无效。