2010-08-07 67 views
6

爲什麼不能使用evalwith聲明下訪問範圍變量?eval如何在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控制檯)。

如果有人想知道我想要什麼憎惡,那就需要「邪惡」evalwith - 我試圖看看我是否能夠獲得一個函數(用作回調函數)在另一個函數中執行上下文,而不是它定義的那個。不,我可能(咳嗽)不會在任何地方使用..比任何事情都更好奇。

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

在其瀏覽器中你得到這個行爲?你在某個控制檯上運行代碼嗎? – CMS 2010-08-07 19:15:56

+0

@CMS:Chrome 5.0.375.125測試版使用內置的開發者控制檯。編輯:我剛剛嘗試與Firefox(螢火蟲),並按預期工作。必須是您所說的瀏覽器錯誤。 – 2010-08-07 19:19:58

+0

@Daniel - 它可以在Chrome 6.0.472.22中正常運行,如果這有助於任何 – 2010-08-07 19:24:47

回答

5

這是一個只能從WebKit的控制檯重現的錯誤,當從FunctionExpression調用eval時,它具有綁定調用者上下文的問題。

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
0

Eval總是在全局範圍內運行,不是嗎?

+0

不,直接調用'eval'將使用調用上下文(調用者詞法和變量環境),間接調用ECMAScript 5中的eval,例如:'var foo = eval; foo('code');'將使用全局上下文以及Function構造函數。 – CMS 2010-08-07 19:50:22

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控制檯卻沒有)。它可能是一個錯誤或(更可能)它可能按預期工作。

0

把EVAL並用之外,新bowsers包括ecma5 Function.prototype.bind方法調用在一些選定的對象的範圍的函數。

對於舊的瀏覽器,你可以僞造它 -

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

請注意,* fallback函數*不符合標準,它不能預先填充或* curry *具有已知參數的函數。 [這個實現](http://stackoverflow.com/questions/2025789/preserving-a-reference-to-this-in-javascript-prototype-functions/2025839#2025839)是最接近你可以遵守的ES5規格,運行在ES3引擎上。另外* binding *函數不會訪問調用者的變量或詞法環境(看起來OP最終需要),它只能確保'this'值(和* curried *參數)將被持久化。 – CMS 2010-08-08 01:23:47