亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何“遞歸地”將調用其他作用域函數的 javascript 函數字符串化?

如何“遞歸地”將調用其他作用域函數的 javascript 函數字符串化?

Helenr 2021-12-12 16:09:21
因為 javascript 函數是不可序列化的,為了有時(盡管很少)將它們傳遞到新的上下文中,將它們字符串化然后稍后重新評估它們會很有用,例如:const foo = () => { // do something }const fooText = foo.toString()// later... in new context & scopeconst fooFunc = new Function(' return (' + fooText + ').apply(null, arguments)')fooFunc() // works!但是,如果foo引用另一個 function bar,則范圍未字符串化,因此如果bar未在新上下文中定義,則評估的 foo 函數將在調用時拋出錯誤。我想知道是否有辦法遞歸地對函數進行字符串化?也就是說,不僅將父函數字符串化,還要將父函數調用的子函數的內容字符串化。例如:let bar = () => { alert(1) }let foo = () => { bar() }// what toString doeslet fooString = foo.toString()console.log(fooString) // "() => { bar() }"// what we wantlet recursiveFooString = foo.recursiveToString()console.log(recursiveFooString) // "() => { alert(1) }"如果您對如何完成諸如“recursiveToString”之類的事情有任何想法,請告訴我
查看完整描述

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(變量名稱到給定范圍內的值的內部映射)。


查看完整回答
反對 回復 2021-12-12
?
jeck貓

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,它沒有在任何地方公開。


所以即使是這個簡單的函數也不能可靠地序列化;對更復雜的事情似乎沒有希望。


查看完整回答
反對 回復 2021-12-12
?
波斯汪

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();


查看完整回答
反對 回復 2021-12-12
  • 3 回答
  • 0 關注
  • 168 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號