7


0

evalがwithステートメントの下でスコープ変数にアクセスできないのはなぜですか?

なぜ with文の下でevalを使用してスコープ変数にアクセスできないのですか?

例えば:

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

編集:知識豊富なCMSが指摘したように、これはブラウザーのバグ(WebKitコンソールを使用するブラウザー)のようです。

もし誰かが私が考え出そうとしている憎悪が「悪」の「eval」と「with」の両方を必要とするだろうと思っていたら-別の関数で実行される関数(コールバックとして使用)を取得できるかどうかを確認しようとしていた定義されたコンテキストではなく、コンテキスト。 いいえ、私は_おそらく_(咳)これをどこでも使用しません。 何よりも好奇心が強い。

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

4 Answer


6


これはWebKitのコンソールからのみ再現可能なバグです。`eval`が `FunctionExpression`から呼び出されると、呼び出し側のコンテキストをバインドする際に問題が発生します。

`eval`の直接呼び出しが行われると、予想される評価されたコードは両方の変数環境を共有するはずです:

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

また、語彙環境:

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

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

上記の関数では、 `localVar`はグローバルコンテキストではなく、呼び出し元の字句環境で宣言する必要があります。

`FunctionDeclaration`sの場合、次のことを試みた場合の動作は完全に正常です。

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

And

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

Windows Vista SP2で実行されている次のブラウザで問題を再現できました。

  • Chrome 5.0.375.125

  • Chrome 6.0.472.25 dev

  • Safari 5.0.1

  • WebKitナイトリービルドr64893


1


(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")

すべて正常に動作します:FF / Chrome / Safari / IEのhttp://polyfx.com/jstest.html。

さまざまなコンソールからコードのスニペットを実行する際の問題は、コンソールが通常コンテキストにねじ込まれていることです。 (すなわち Firebugコンソールはそうですが、Chromeコンソールはグローバルコンテキストで適切にラッピングしているようには見えません)。 バグである可能性もありますし、(おそらく)意図したとおりに機能している可能性もあります。


0


Evalは常にグローバルスコープで実行されます。


0


evalとは別に、新しいバウザーには、選択したオブジェクトのスコープ内の関数を呼び出すecma5 Function.prototype.bindメソッドが含まれています。

古いブラウザの場合は、偽造することができます-

Function.prototype.bind= Function.prototype.bind || function bind(scope){
    var method= this;
    return function(){
        method.apply(scope, arguments);
    }
}