Por que eval não tem acesso às variáveis ​​com escopo definido em uma instrução with?

StackOverflow https://stackoverflow.com/questions/3431689

  •  26-09-2019
  •  | 
  •  

Pergunta

Por que você não pode acessar variáveis ​​com escopo usando eval debaixo de with declaração?

Por exemplo:

(function (obj) { 
   with (obj) {
      console.log(a); // prints out obj.a
      eval("console.log(a)"); // ReferenceError: a is not defined
   }
})({ a: "hello" })

EDITAR:Como apontou o experiente CMS, isso parece ser um bug do navegador (navegadores que usam o console WebKit).

Se alguém estivesse se perguntando que abominação eu estava tentando inventar, isso exigiria tanto o "mal" eval e with - Eu estava tentando ver se conseguia executar uma função (usada como retorno de chamada) em outro contexto, em vez daquele em que foi definida.E não, eu provavelmente (tosse) não vou usar isso em lugar nenhum..mais curioso do que qualquer coisa.

(function (context,fn) { 
    with (context) 
       eval("("+fn+")()"); 
})({ a: "hello there" }, function () { console.log(a); })
Foi útil?

Solução

Este é um bug reproduzível apenas no console do WebKit, ele apresenta problemas para vincular o contexto do chamador quando eval é invocado de um FunctionExpression.

Quando uma chamada direta de eval é feito, o código avaliado conforme o esperado deve compartilhar o ambiente variável:

(function (arg) {
  return eval('arg');
})('foo');
// should return 'foo', throws a ReferenceError from the WebKit console

E também o ambiente lexical:

(function () {
  eval('var localVar = "test"');
})();

typeof localVar; // should be 'undefined', returns 'string' on the Console

Na função acima localVar deve ser declarado no ambiente lexical do chamador, não no contexto global.

Para FunctionDeclarations o comportamento é completamente normal, se tentarmos:

function test1(arg) {
  return eval('arg');
}
test1('foo'); // properly returns 'foo' on the WebKit console

E

function test2() {
  eval('var localVarTest = "test"');
}
test2();
typeof localVarTest; // correctly returns 'undefined'

Consegui reproduzir o problema nos seguintes navegadores executados no Windows Vista SP2:

  • Cromo 5.0.375.125
  • Desenvolvedor do Chrome 6.0.472.25
  • Safári 5.0.1
  • WebKit Nightly Build r64893

Outras dicas

(function (obj) {
   with (obj) {
      alert(a); // prints out obj.a
      eval("alert(a)"); // ReferenceError: a is not defined
   }
})({ a: "hello from a with eval" })

function testfunc(a) { eval("alert(a)"); } testfunc("hello from a testfunc eval");

(function (a) { eval("alert(a)"); })("hello from a function constructor eval")

Tudo funciona bem: http://polyfx.com/jstest.html em FF/Chrome/Safari/IE.

O problema de executar trechos de código de vários consoles é que os consoles geralmente atrapalham o contexto.(ou seja,o console do Chrome não parece estar agrupando as coisas corretamente no contexto global, enquanto o console do Firebug o faz).Pode ser um bug ou (mais provavelmente) estar funcionando conforme o esperado.

Eval sempre roda em escopo global, não é?

Deixando de lado eval e with, os novos bowsers incluem o método ecma5 Function.prototype.bind para chamar uma função no escopo de algum objeto selecionado.

Para navegadores mais antigos, você pode fingir-

Function.prototype.bind= Function.prototype.bind || function bind(scope){
    var method= this;
    return function(){
        method.apply(scope, arguments);
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top