2015-05-05 27 views
3

所以我有這樣的代碼:是否可以在新函數()後更改函數的作用域?

function fn(a){ 
    var f=(new Function("return a")); 
    return f(); 
} 
fn(7)//ReferenceError: a is not defined 

同樣的問題與局部變量:

function fn(){ 
    var a=7; 
    var f=new Function("return a"); 
    return f(); 
} 
fn(7)//ReferenceError: a is not defined 

我希望它返回一個,但新的功能不能看到, 它只能看到全球一個

var a=1; 
function fn(a){ 
    var f=(new Function("return a")); 
    return f(); 
} 
fn(7)//1 

正常的初始化函數可以看到參數。

function fn(a){ 
    var f=function(){return a}; 
    return f(); 
} 
fn(7)//7 

我需要調用我的項目中的基本構造函數,並且不能使用全局變量。 我知道,我可以給參數傳遞給新創建的功能,可以解決這一點,與這樣稱呼它:

function fn(a){ 
    var f=(new Function('a',"return a")); 
    return f(a); 
} 
fn(7)//7 

而且還可以使用一些分析功能,有些愣神長法建立傳入的參數到達這樣的:

function parsargs(funct){ 
    //some parsing methodes giving back argument name list from funct.toString() 
    return "['a','b']";//like this 
} 


function fn(a,b){ 
    var arrgstr,retfunc; 

    arrgstr=""; 
    for(var i in arguments) 
    { 
    if(i<arguments.length-1) 
     arrgstr+=arguments[i]+","; 
    else 
     arrgstr+=arguments[i]; 
    } 
    //return arrgstr; 
    retfunc="var f=new Function("+parsargs()+",'return b*a');return f("+arrgstr+")"; 
    return (new Function(retfunc))(); 
} 
fn(7,4)//28 

但一定要到達局部變量和函數以及更簡單的方法... 有什麼建議?

PS: 我試圖在項目

我更換的eval()是我原來問題的一個簡化版本: fiddle

答案是NO ...

+1

你想讓它與ES6和嚴格模式(即不使用arguments.callee)兼容嗎?你想能夠自由地命名fn的參數嗎? –

+1

我有強烈的感覺,這是一個XY問題。什麼是真正的目標? –

+1

arguments.callee不是我的選擇... – szinter

回答

1

你可以call新功能的引用,你需要的局部變量的上下文:

function f(a) { 
    var b = 30; 
    return new Function("return this.a + this.b").call({ a: a, b: b }) 
} 

f(10) // 40 
+0

不直接回答這個問題,但你以前的答案指出了我有這個問題的基本問題,所以我會接受這個答案,因爲你給了我一個可以使用的工作。 – szinter

1

爲什麼這種工作並不容易,因爲JavaScript不會將變量放在範圍內。相反,它解析函數體(儘可能好)並確定代碼將需要哪些變量。然後它將查找外部範圍中的變量,爲它們創建引用並將這些引用附加到新函數。當它最終將被執行時,這是外部作用域內的變量可以在函數內部訪問的。

你想從一個字符串主體構建一個函數。 JavaScript無法分辨正文將使用哪些變量,因此它不會使這些變量可用。

,使之成爲功能參數正常工作,使用apply():

function fn(a){ 
    var argref = arguments; // create reference to the arguments of fn() and hence to a or any other arguments 
    var func = new Function("return arguments[0]"); 
    var wrapper = function() { 
     return func.apply(null, argref); 
    }; 
    return wrapper; 
} 

請注意,您仍然無法通過名稱引用參數,因爲代碼永遠不會指定了的func參數的名字是 - JavaScript可以神奇地讀你的想法,做你想做的事。如果你想通過名字訪問參數,你需要告訴解釋器的名字。

這個問題有一些代碼如何從一個函數引用確定名稱:How to get function parameter names/values dynamically from javascript

我沒有看到一個方法,使局部變量可用而不將它們傳遞給fn()作爲參數。即使你在fn()內使用它們,當最終執行func()時,它們也會超出範圍。

一個簡單的解決辦法是將對象傳遞給fn()

function fn(conf) { 
    var func = new Function('conf', "return conf.a"); 
    var wrapper = function(conf) { 
     return func.apply(null, conf); 
    }; 
    return wrapper; 
} 

fn({a:7}); 
+0

感謝您的回答,我添加了一個小提琴在哪裏是原始代碼的簡化版本。我想將eval()替換爲新的Function()。 你能看看嗎?你可能會有一些建議。 – szinter

+0

你爲什麼要替換'eval()'? –

2

你確切的問題並不清楚,但是,假如你可以使用arguments.callee(即非嚴格模式),並要能夠在fn有任何參數的名字,你「可能」做到這一點:

function fn(a,b){ 
    var strargs = arguments.callee.toString().match(/\(([^\)]*)\)/)[1]; 
    return (new Function(strargs.split(","),"return a+b")).apply(null,arguments); 
} 
console.log(fn(7, 3)) // 10 

但是我有一個強烈的感覺,這是一個XY的問題,我們應該能給出更多有用的答案知道真正的原問題解決。

+0

感謝您的回答,我添加了一個小提琴在哪裏是原始代碼的簡化版本。我想將eval()替換爲新的Function()。你能看看嗎?你可能會有一些建議。 – szinter

+0

@szinter你可以解析你當前正在評估的字符串,但唯一的乾淨和可靠的解決方案將是定義你當前正在評估的結構模型,並傳遞一個對象而不是免費代碼。這個模型當然完全取決於你的應用邏輯和領域。 –

+0

這個解決方案取代了基於代碼的惡意代碼(8 KLOC〜) – szinter

1

new Functiondoesn't create a closure context,但eval呢。

這裏是一個低技術的方式來建立一個任意評價主體和訪問調用範圍功能:

function f(a) { 
    return eval("(function() { return a })")() 
} 

f(10) // 10 
+0

是的,我忘了告訴我,我試圖在項目中替換eval()sry – szinter

+0

刪除它的原因是什麼? – joews

+0

性能問題。 – szinter

相關問題