7

evalunderwithステートメントを使用してスコープ変数にアクセスできないのはなぜですか?

例えば:

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

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

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

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

4 に答える 4

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では、グローバルコンテキストではなく、呼び出し元の字句環境で宣言する必要があります。

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

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

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

WindowsVistaSP2で実行されている次のブラウザで問題を再現することができました。

  • Chrome 5.0.375.125
  • Chrome 6.0.472.25 dev
  • Safari 5.0.1
  • WebKit Nightly Build r64893
于 2010-08-07T20:25:43.980 に答える
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 。

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

于 2010-08-07T20:17:49.067 に答える
0

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

于 2010-08-07T19:45:03.190 に答える
0

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

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

Function.prototype.bind= Function.prototype.bind || function bind(scope){
    var method= this;
    return function(){
        method.apply(scope, arguments);
    }
}
于 2010-08-07T23:52:05.753 に答える