繁体   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