Вызов eval() в определенном контексте
У меня есть следующий класс javaScript:
A = (function() {
a = function() { eval(...) };
A.prototype.b = function(arg1, arg2) { /* do something... */};
})();
Теперь предположим, что в eval() я передаю строку, содержащую выражение, вызывающее b, с некоторыми аргументами:
b("foo", "bar")
Но тогда я получаю ошибку, что b не определен. Поэтому мой вопрос: как вызвать eval в контексте класса A?
Ответы
Ответ 1
На самом деле вы можете сделать это с помощью абстракции с помощью функции:
var context = { a: 1, b: 2, c: 3 };
function example() {
console.log(this);
}
function evalInContext() {
console.log(this); //# .logs '{ a: 1, b: 2, c: 3 }'
eval("example()"); //# .logs '{ a: 1, b: 2, c: 3 }' inside example()
}
evalInContext.call(context);
Таким образом, вы call
выполняете функцию с нужным context
и запускаете eval
внутри этой функции.
Как ни странно, это работает для меня локально, но не на Plunkr!?
Для краткой (и, возможно, суккулентной) версии, которую вы можете дословно скопировать в свой код, используйте это:
function evalInContext(js, context) {
//# Return the results of the in-line anonymous function we .call with the passed context
return function() { return eval(js); }.call(context);
}
РЕДАКТИРОВАТЬ: Не путайте this
и "охват".
//# Throws an error as 'this' is missing
console.log(evalInContext('x==3', { x : 3}))
//# Works as 'this' is prefixed
console.log(evalInContext('this.x==3', { x : 3}))
Хотя один мог это сделать:
function evalInScope(js, contextAsScope) {
//# Return the results of the in-line anonymous function we .call with the passed context
return function() { with(this) { return eval(js); }; }.call(contextAsScope);
}
для преодоления разрыва, это не то, что задал OP-вопрос, и он использует with
, а , как говорит MDN:
Использование оператора with не рекомендуется, так как это может быть источником запутанных ошибок и проблем совместимости. Смотрите "Неоднозначность Contra" пункт в разделе "Описание" ниже для получения подробной информации.
Но это работает и не слишком "плохо" (что бы это ни значило), пока кто-то знает о странности, которая может возникнуть в результате такого вызова.
Ответ 2
Как вызвать eval в заданном контексте? 3 слова. Используйте закрытие.
var result = function(str){
return eval(str);
}.call(context,somestring);
Bam.
Ответ 3
Изменить
Несмотря на то, что eval.call и eval.apply не принудительно передают контекст, вы можете использовать закрытие для принудительного выполнения eval в требуемом контексте, как указано в ответах @Campbeln и @user3751385
Мой первоначальный ответ
Это невозможно. Eval вызывается только в локальном контексте (используется напрямую) или в глобальном контексте (даже если вы используете eval.call).
Например,
a = {};
eval.call(a, "console.log(this);"); //prints out window, not a
Для получения дополнительной информации просмотрите эту замечательную статью здесь
Ответ 4
Определенно не правильный ответ, и, пожалуйста, не используйте инструкцию with
, если вы не знаете, что делаете, но для любопытных вы можете сделать это
Пример
var a = {b: "foo"};
with(a) {
// prints "foo"
console.log(eval("b"));
// however, "this.b" prints undefined
console.log(eval("this.b"));
// because "this" is still the window for eval
// console.log(eval("this")); // prints window
// if you want to fix, you need to wrap with a function, as the main answer pointed out
(function(){
console.log(eval("this.b")); // prints foo
}).call(a);
}
// so if you want to support both
with (a) {
(function (){
console.log("--fix--");
console.log(eval("b")); // foo
console.log(eval("this.b")); // foo
}).call(a);
}
Ответ 5
Вот статья, в которой обсуждается запуск eval()
в разных контекстах:
http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
Обычно вы делаете это с помощью eval.call()
или eval.apply()
.
Здесь также представлена информация о eval()
и ее вариантах использования:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/eval
Ответ 6
Это решило мою проблему.
function evalInContext(js, context) {
return function(str){
return eval(str);
}.call(context, ' with(this) { ' + js + ' } ');
}
для реализации аналогично "Дом-если"
<template if="{{varInContext == ''}}"> ... </template>
пример
var myCtx = {table: 'Product', alias: 'ProductView'};
evalInContext(' table == "" ', myCtx); //#false
evalInContext(' alias == "ProductView" ', myCtx); //#true
Ответ 7
var evalWithinContext = function(context, code)
{
(function(code) { eval(code); }).apply(context, [code]);
};
evalWithinContext(anyContext, anyString);
Ответ 8
Другой Bam!
eval('(function (data) {'+code+'})').call(selector,some_data);
Этот пример сохранит ваш контекст и отправит некоторые данные. В моем случае это несколько DOM-селектор
Ответ 9
Для меня работало использование конструктора Function
и его вызов в указанном контексте:
var o = {
x: 10
}
(new Function('console.log(this.x)')).call(o);
Ответ 10
Включает в себя контекст плюс функцию плюс выражение. Контекст должен быть плоской структурой (без вложенных элементов), а функция должна называться 'fn' внутри строкового выражения. Отпечатки ответов 11:
var expression = "fn((a+b)*c,2)";
var context = { a: 1, b: 2, c: 3 };
var func = function(x,y){return x+y;};
function evaluate(ex, ctx, fn) {
return eval("var "+JSON.stringify(ctx).replace(/["{}]/gi, "").replace(/:/gi, "=")+", fn="+fn.toString()+";"+ex);
}
var answer = evaluate(expression, context, func);
console.log(answer);