3 回答

TA貢獻1942條經驗 獲得超3個贊
做到這一點的唯一好方法是從包含所有函數foo最終引用的父作用域開始。例如,對于您的fooand bar,如果您想傳遞foo到另一個bar可調用的上下文中,請傳遞一個同時聲明fooandbar并返回的函數foo。例如:
const makeFoo = () => {
let bar = () => { alert(1) }
let foo = () => { bar() }
return foo;
};
const makeFooStr = makeFoo.toString();
// ...
const makeFooFunc = new Function(' return (' + makeFooStr + ').apply(null, arguments)');
const foo = makeFooFunc();
foo();
很好地實現這類事情確實需要像上面那樣有預謀的設計(不幸的是)。在字符串化時,您不能真正包含所有祖先 LexicalEnvironments(變量名稱到給定范圍內的值的內部映射)。

TA貢獻1909條經驗 獲得超7個贊
我想知道是否有辦法遞歸地對函數進行字符串化?
我認為我們可以相當簡單地證明這在一般情況下是不可能的。
讓我們想想這兩個函數
const greet = (greeting) => (name) => `${greeting} ${name}`
const sayHi = greet ('Hi')
sayHi ('Jane') //=> "Hi Jane"
雖然你foo和bar例子,我們可能想象的東西,審查的功能,在當前范圍內做基于解析功能,并知道什么實際使用的局部變量的擴展功能字符串化使用提供一切的身體。(我猜這也是不可能的,原因與賴斯定理有關,但我們當然可以想象。)
但在這里,請注意
sayHi.toString() //=> "(name) => `${greeting} ${name}`"
因此sayHi取決于一個未存儲在我們當前作用域中的自由變量,即greeting. 我們只是沒有在任何地方存儲用于創建該函數的“Hi”,除了在 的閉包范圍內sayHi,它沒有在任何地方公開。
所以即使是這個簡單的函數也不能可靠地序列化;對更復雜的事情似乎沒有希望。

TA貢獻1811條經驗 獲得超4個贊
我最終滾動的靈感來自@CertainPerformance 的回答。
訣竅是構建一個定義所有子被調用函數的函數。然后你就擁有了字符串化父函數所需的一切。
注意:為了允許從其他文件導入被調用函數,我決定用被調用定義以編程方式構建一個字符串,而不是最初在同一范圍內定義它們。
代碼:
// original function definitions (could be in another file)
let bar = () => { alert(1) }
let foo = () => { bar() }
const allCallees = [ bar, foo ]
// build string of callee definitions
const calleeDefinitions = allCallees.reduce(
(definitionsString, callee) => {
return `${definitionsString} \n const ${callee.name} = ${callee.toString()};`;
},
"",
);
// wrap the definitions in a function that calls foo
const fooString = `() => { ${calleeDefinitions} \n return foo(); \n }`;
console.log(fooString);
/**
* fooString looks like this:
* `() => {
* const bar = () => { alert(1) };
* const foo = () => { bar() };
* return foo();
* }`
**/
// in new context & scope
const evaluatedFoo = new Function(' return (' + fooString + ').apply(null, arguments)');
// works as expected
evaluatedFoo();
添加回答
舉報