簡體   English   中英

如何使用JavaScript動態更改函數的內容

[英]How to dynamically change the contents of a function using JavaScript

為了幫助理解此功能,該功能在html頁面中並且已生成,因此我無法更改生成的代碼:

function Update_qu7260() {
  var newVal = ''
  for( var idx = 0; idx < 2; idx++ )
  {
    var test
    if( idx == 0 ) test = text7263
    else if( idx == 1 ) test = text7265
    if( test.matchObj ) newVal += test.leftSel + "-" + test.matchObj.rightSel + ","
  }
  newVal = newVal.substring( 0, newVal.length-1 )
  VarQuestion_0001.set( newVal )
  qu7260.hasBeenProcessed=false;
  doImmFeedback('qu7260');
}
var qu7260 = new Object();
...
qu7260.updFunc = Update_qu7260;
var qObj=[qu7260];

請注意,在上面的數字“ 7260”中,數字從1開始,所以它們很多,並且每個Update_###()都不同,因此我無法用“硬接線”代碼重寫它們。 我的代碼在外部JavaScript文件中,並在onLoad上執行:

...
var updFunc = qObj[0].updFunc.toString();
if(updFunc.indexOf('doImmFeedback(')!=-1){
  updFunc = updFunc.replace('doImmFeedback','doImmQuestionFeedback');  // do my function
  updFunc = updFunc.replace('function ','');  // remove the word function
  var funcName = updFunc.substr(0,updFunc.indexOf('('));  // get the function name e.g. Update_qu7260
  updFunc = "window['" + funcName + "']=function" + updFunc.replace(funcName,'');
  eval(updFunc);
}
...

當我將eval()更改為alert()時,我可以看到它是正確的,但是,eval()沒有引發任何錯誤,並且未調用我的函數doImmQuestionFeedback 當我隨后執行alert(qObj[0].updFunc.toString())我看到了原始功能。

看來我提供的信息太復雜了,因此以下代碼是一個更好的示例:

function hi(){alert('hi');}
function changeHi(){
   hi(); // I get an alert box with hi
   newHi = "function hi(){alert('hi there');}"
   eval(newHi);
   hi(); // I get an alert box with hi
   window.setTimeout('hi()',500); // I get an alert box with hi
}
window.setTimeout('changeHi()',500);

以下是原始問題:

我有一個未創建的預定義函數,但是,我知道它的名稱,因此我可以獲取該函數本身,然后通過執行以下操作對其進行更改:

var funcText = window.updateFunc.toString();
funcText = funcText.replace('doSomeOtherFunction(','doMyFunction(');

我如何更新實際函數,以便它將執行以前做過的所有事情,除了現在將調用doMyFuntion()?

下面是一個示例,可以幫助您直觀地了解我想做什么,我需要更改的實際功能非常復雜。 我有:

function updateFunc(whatToUpdate,true){
   ... - do lots of stuff.
   var retVal = doSomeOtherFunction(whatToUdate);
   ... - do lots of stuff based on retVal
}

我需要將其更改為:

function updateFunc(whatToUpdate,true){
   ... - do lots of stuff
   var retVal = doMyFunction(whatToUdate);
   ... - do lots of stuff based on retVal, I have had a chance to change retVal
}

然后,我的函數要做的第一件事就是調用doSomeOtherFunction()來檢查/更改返回的值,然后將該值返回給updateFunc()。

我試圖操縱上面的funcText來:

funcText = 'window.updateFunc = function(...';
eval(funcText);

沒有成功。

這可能已經足夠關閉您想要的內容。

假設您具有此原始功能:

function originalFunc(val) {
    // this function converts input string to upper case
    return val.toUpperCase();
}

現在,您想在執行該函數之前或之后將其重寫為某些內容(在此示例中,我們在此函數之前或之后執行當然並不重要)。

// we preserve orignal function
var originalFunc_save = originalFunc;

// now we override the original function with this block    
var originalFunc = function(text) {
    // lets call the orignal function
    text = originalFunc_save(text);

    // now do our custom thing
    return text.split('').reverse().join('');
}

因此,我們的測試應該可以工作。

var text = 'This is a test';
console.log(originalFunc(text));

輸出:

TSET A SI SIHT

如果必須重寫類中的函數,則此方法也適用。 我們唯一需要注意的是選擇一個不會干擾原始類代碼的已保存名稱。 _save可能不夠好,但是您明白了。

更新:我正在上面的代碼中更新,以使用指向原始函數的字符串變量。 我認為這就是OP想要的。

由某些庫定義的原始代碼

function originalFunc(val) {
    // this function converts input string to upper case
    return val.toUpperCase();
}

現在,我們使用func字符串變量指向該函數並執行它。

var text = 'This is a test';
var func = 'originalFunc';
text = window[func](text);
console.log(text);

輸出:當然,我們得到了最初的預期結果,因為我們沒有覆蓋它。

THIS IS A TEST

現在,我們使用指向函數的字符串編寫代碼以覆蓋原始函數行為。

// let's define a new function string
var funcSaved = func + '___saved';

// now preserve the original function code
window[funcSaved] = window[func];

// override the original function code block
window[func] = function(text) {
    // lets call the orignal function
    text = window[funcSaved](text);

    // now do our custom thing
    return text.split('').reverse().join('');
}

// let's test the code
text = 'This is a test';
text = window[func](text);
console.log(text);

輸出:

TSET A SI SIHT

我認為您這樣做的方式太復雜了。 如果僅在doMyFunctiondoSomeOtherFunction之間進行切換,則可以僅在某處創建一個標志,告訴您在if語句中使用一個或另一個。

如果要使用事先不知道的名稱調用函數,並且僅在運行時獲得名稱,則可以接受該函數作為參數調用,也可以接受該函數的名稱作為參數,然后像這樣調用它: var retVal = window[functionName](); (假設functionNamewindow對象的屬性)。

我強烈建議直接接受函數作為參數,因為該函數可能未在全局范圍內定義。

編輯:在您澄清之后,我想,我可以給您滿意的答案:

如果您有一個字符串,如var functionString = "function updateFunc(whatToUpdate){var retVal = doMyFunction(whatToUpdate);}";

您可以使用Function對象定義函數: window.updateFunc = new Function("whatToUpdate", "return (" + functionString + ")(whatToUpdate)"); 這將替換已經存在的函數,並且只要您知道並指定參數,就可以為它提供任何想要的有效函數字符串。

如果我理解正確,則您想覆蓋外部功能。 您可以使用以下代碼來實現

//Someone else's function
function externalFunction(foo){
    return "some text";
}

//Your function
function myFunction(value){
  //Do something
}

//Override
var externalFunction = (function(){
    var original = externalFunction; //Save original function

    return function(){
        var externalFunctionReturnValue = original.apply(this, arguments);

        return myFunction(externalFunctionReturnValue);
    }
})();

我強烈建議不要使用eval,但是由於您想從字符串中解析javascript:

function hi(){alert('hi');}
function changedHi(){
   hi(); // I get an alert box with hi
   newHi = "window['hi'] = function(){alert('hi there');}"
   eval(newHi);
   hi(); // I get an alert box with hi there
   window.setTimeout('hi()',500); // I get an alert box with hi there
}
window.setTimeout('changedHi()',500);

更新:

此代碼段有效,它是您的原始代碼:

  <script type="text/javascript">
     function doImmFeedback(foo){
        console.log("DoImmFeedback: " + foo);
      }

      function Update_qu7260() {
        console.log("Some code")
        doImmFeedback('qu7260');
      }
   </script> 

    <script type="text/javascript">
      var qu7260 = new Object();
      qu7260.updFunc = Update_qu7260;
      var qObj=[qu7260];

      var updFunc = qObj[0].updFunc.toString();
      if(updFunc.indexOf('doImmFeedback(')!=-1){
        updFunc = updFunc.replace('doImmFeedback','doImmQuestionFeedback');  // do my function
        updFunc = updFunc.replace('function ','');  // remove the word function
        var funcName = updFunc.substr(0,updFunc.indexOf('('));  // get the function name e.g. Update_qu7260
        updFunc = "window['" + funcName + "']=function" + updFunc.replace(funcName,'');
        console.log(updFunc);
        eval(updFunc);
      }

      function doImmQuestionFeedback(foo){
        //Your function
        console.log("doImmQuestionFeedback: " + foo);
      }

      Update_qu7260(); //This executes your doImmQuestionFeedback
   </script>

因此,如果您的函數未運行,則您的函數不在全局范圍內,或者正在發生其他情況,因此我們無法知道是否沒有更多信息。 檢查您的開發者控制台是否存在javascript錯誤。

我相信這是一個有效的用例被遺忘的JavaScript with功能。

基本思路:你叫原updateFunc提供自己的版本doSomeOtherFunction使用它with命名空間注入:

function updateFunc(whatToUpdate,true){
   ... - do lots of stuff.
   var retVal = doSomeOtherFunction(whatToUdate);
   ... - do lots of stuff based on retVal
}


function patchUpdateFunc() {

  var original_doSomeOtherFunction = window.doSomeOtherFunction;
  var original_updateFunc = window.updateFunc;

  function doMyFunction() { 
    // call original_doSomeOtherFunction() here,
    // do your own stuff here.
  };

  window.updateFunc = function() {
    with ({doSomeOtherFunction: doMyFunction}) {
       return original_updateFunc.apply(this, arguments); 
    }
  }
}

patchUpdateFunc();

您可以克隆updateFunc函數,自行決定對其進行編輯,然后在隨后的工作中使用它。

    function updateFunc(whatToUpdate, param){ // the initial function
        ...
        var retVal = doSomeOtherFunction(whatToUpdate);
        return retVal;
    }

    // formation of unnamed function as string
    var newfunc = updateFunc.toString().replace('function updateFunc', 'function ').replace('doSomeOtherFunction(', 'doMyFunction(');

    function doMyFunction(whatToUpdate){ // your new function, just for example
        console.log(parseInt(whatToUpdate) * 10);
    }

    var newUpdateFunc;
    // declaring new version of 'updateFunc' function
    // which is stored in 'newUpdateFunc' variable 
    eval("newUpdateFunc = " + newfunc); 

    newUpdateFunc(3); // outputs '30'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM