Подтвердить что ты не робот

Вызов eval() в определенном контексте

У меня есть следующий класс javaScript:

A = (function() {
   a = function() { eval(...) };
   A.prototype.b = function(arg1, arg2) { /* do something... */};
})();

Теперь предположим, что в eval() я передаю строку, содержащую выражение, вызывающее b, с некоторыми аргументами:

 b("foo", "bar")

Но тогда я получаю ошибку, что b не определен. Поэтому мой вопрос: как вызвать eval в контексте класса A?

4b9b3361

Ответ 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);