ti-enxame.com

chamando eval () em contexto particular

Eu tenho seguindo javaScript "class":

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

Agora vamos supor que em eval () eu estou passando string que contém a expressão chamando b com alguns argumentos:

 b("foo", "bar")

Mas então eu recebo erro que b não está definido. Então, minha pergunta é: como chamar eval no contexto da classe A?

41
mnowotka

Na verdade você can consegue isso com uma abstração através de uma função:

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

Então você call a função com o context que você deseja e executa eval dentro dessa função.

Estranhamente, isso parece estar funcionando para mim localmente, mas não em Plunkr !?

Para uma versão sucinta (e discutivelmente suculenta;) você pode copiar textualmente em seu código, use isto:

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);
}
50
Campbeln

Como chamar eval em um determinado contexto? 3 palavras. Use um fechamento.

var result = function(str){
  return eval(str);
}.call(context,somestring);

Bam.

25
user3751385

Editar

Mesmo assim, eval.call e eval.apply não forçam o contexto a ser passado corretamente, você pode usar um encerramento para forçar o eval a executar no contexto requerido, como mencionado nas respostas de @Campbeln e @ user3751385

Minha resposta original

Isso não é possível. O Eval é chamado apenas no contexto local (é usado diretamente) ou no contexto global (mesmo se você usar eval.call).

Por exemplo, a = {}; eval.call(a, "console.log(this);"); //prints out window, not a

Para mais informações, veja este great artigo aqui

15
everconfusedGuy

definitivamente não é a resposta certa, e por favor não use a instrução with, a menos que você saiba o que está fazendo, mas para os curiosos, você pode fazer isso

Exemplo

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

with é a tentativa fracassada de criar escopos de bloco dentro de funções, do tipo que ES6's let foi projetado para fazer. (mas não exatamente, abra e leia os links dos recursos)

7
bentael

Aqui está um artigo que discute a execução da eval() em diferentes contextos:

http://weblogs.Java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context

Normalmente você faz isso com eval.call() ou eval.apply().

Aqui também estão informações sobre eval() e seus casos de uso:

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/eval

6
Mikko Ohtamaa
var evalWithinContext = function(context, code)
{
    (function(code) { eval(code); }).apply(context, [code]);
};
evalWithinContext(anyContext, anyString);
2
Andrea Serreli

Outro Bam!

eval('(function (data) {'+code+'})').call(selector,some_data);

Este exemplo irá manter o seu contexto e enviar alguns dados. No meu caso, é um seletor de algum DOM

1
Artur

O que funcionou para mim foi usar o construtor Function e chamá-lo no contexto especificado:

var o = {
  x: 10
}

(new Function(`console.log(this.x)`)).call(o);

Isso de alguma forma não funciona no console do navegador, mas funciona em outro lugar.

0
Rytis Alekna

Isso resolveu meu problema.

 function evalInContext(js, context) {
    return function(str){
        return eval(str);
    }.call(context, ' with(this) { ' + js + ' } ');
}

para implementação semelhante a "Dom-if"

<template if="{{varInContext == ''}}"> ... </template>

Exemplo

var myCtx = {table: 'Product', alias: 'ProductView'};
evalInContext(' table == "" ', myCtx); //#false
evalInContext(' alias == "ProductView" ', myCtx); //#true
0
Ilario Junior