2016-07-29 3 views
5

Я динамически создаю функцию в экземпляре Foo1 с именем test. Я создаю эту функцию, используя eval. Я ожидал бы, что эта функция будет иметь доступ к классу Foo2, однако я получаю ReferenceError: Foo2 is not defined.Javascript `eval()` scope в ES6

Я открыл вопрос с Babel об этом и можно найти here

Если вы хотите, чтобы запустить пример кода самостоятельно, загрузите его с here и следовать инструкциям в README.MD воспроизвести.

Для запуска:

 
npm install 
npm run start 
naviage to localhost:8080 

Вот структура каталога для моего Minimal, Полная и проверяемых, например, в моей среде:

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

package.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 класс к предыдущей версии браузеров, все работает как очарование:

function Foo2() { } 

Foo2.prototype.test = function() { 
    console.log('i\'m working!'); 
}; 

module.exports = Foo2; 
+0

Хорошо я Редактирование вопроса прямо сейчас – frankgreco

+2

Отличное усилие на MCVE, кстати. –

ответ

4

Похоже, что ваш код инкапсулирован в модуль. Объявления верхнего уровня в модулях не globals, но, как вы обнаружили, функции, созданные с помощью new Function, не закрывают контекст, в котором они созданы; они созданы, как если бы они находились в глобальном масштабе.

Как вы указали, new Function не является идеальным, поскольку он обеспечивает для оценки произвольного кода, но если вы управления и может доверять код вы оценивая, что это не обязательно является проблемой. Наличие new Function также в значительной степени влечет за собой способность JavaScript-движка оптимизировать код, где он появляется (поскольку он не может знать, что находится в тексте функции), поэтому лучше всего держать их достаточно изолированными, если сможете.

С new Function уже есть обе эти проблемы, мы можем пойти и использовать eval, который разделяет их: eval работает в текущей области, а не в глобальном масштабе.

eval пример:

// Scoping function so we know for sure we're not creating globals 
 
(function() { 
 
    var foo = "bar"; 
 
    
 
    var algorithm = "console.log(foo);"; 
 
    var f = makeFunction(algorithm); 
 
    f(); 
 
    
 
    // Isolate the impact of eval within makeFunction 
 
    function makeFunction(text) { 
 
    return eval("(function() { " + text + "})"); 
 
    } 
 
})();

Позвольте мне повторить вопросы с помощью eval, просто чтобы быть действительно ясно

  • Это importantt, что вы только eval код вы можете доверие

  • Использование eval в контексте выполнения в основном делает это невозможным для двигателя JavaScript, чтобы оптимизировать код в этом контексте, так держать его изоляции малых функций, если вы можете содержать этот вопрос

+0

Да, я использую классы ES6 здесь и импортирую другие классы ES6 через модули. Как я мог бы затем передать мои функции, созданные с помощью «новой функции», в ту же область действия, что и на самом деле, я набрал эту функцию? – frankgreco

+0

@Frank: Уродливый ответ - «eval». :-) –

+0

Поскольку вы хотите, чтобы eval для «Сделать это функцией», а не просто «Сделай это», я думаю, что для каждой функции вы обернули бы ее в '' function() {} "' – Katana314

Смежные вопросы