3 回答

TA貢獻(xiàn)1942條經(jīng)驗(yàn) 獲得超3個(gè)贊
做到這一點(diǎn)的唯一好方法是從包含所有函數(shù)foo最終引用的父作用域開(kāi)始。例如,對(duì)于您的fooand bar,如果您想傳遞foo到另一個(gè)bar可調(diào)用的上下文中,請(qǐng)傳遞一個(gè)同時(shí)聲明fooandbar并返回的函數(shù)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();
很好地實(shí)現(xiàn)這類事情確實(shí)需要像上面那樣有預(yù)謀的設(shè)計(jì)(不幸的是)。在字符串化時(shí),您不能真正包含所有祖先 LexicalEnvironments(變量名稱到給定范圍內(nèi)的值的內(nèi)部映射)。

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

TA貢獻(xiàn)1811條經(jīng)驗(yàn) 獲得超4個(gè)贊
我最終滾動(dòng)的靈感來(lái)自@CertainPerformance 的回答。
訣竅是構(gòu)建一個(gè)定義所有子被調(diào)用函數(shù)的函數(shù)。然后你就擁有了字符串化父函數(shù)所需的一切。
注意:為了允許從其他文件導(dǎo)入被調(diào)用函數(shù),我決定用被調(diào)用定義以編程方式構(gòu)建一個(gè)字符串,而不是最初在同一范圍內(nèi)定義它們。
代碼:
// 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();
添加回答
舉報(bào)