どのようにして、evalがステートメントでscoped変数にアクセスできないのですか?
-
26-09-2019 - |
質問
どうして 使用してスコープされた変数にアクセスできません eval
aの下 with
声明?
例えば:
(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); })
解決
これは、WebKitのコンソールからのみ再現可能なバグです。 eval
aから呼び出されます 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
と
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
他のヒント
(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")
すべて正常に動作します: http://polyfx.com/jstest.html ff/chrome/safari/ieで。
さまざまなコンソールからコードのスニペットを実行することの問題は、コンソールが通常コンテキストでねじ込まれていることです。 (つまり、Chromeコンソールはグローバルコンテキストで物を適切に包み込んでいないようには見えませんが、FireBugコンソールはそうではありません)。それはバグかもしれませんし、(より可能性が高い)それは意図したとおりに機能している可能性があります。
評価は常にグローバルな範囲で実行されますよね?
評価を脇に置いて、新しいクッパには、選択したオブジェクトの範囲で関数を呼び出すためのecma5 function.prototype.bindメソッドが含まれます。
古いブラウザの場合、あなたはそれを偽造することができます -
Function.prototype.bind= Function.prototype.bind || function bind(scope){
var method= this;
return function(){
method.apply(scope, arguments);
}
}