为自定义 Javascript 函数定义回调

Defining Callbacks for custom Javascript Functions

场景是我正在编写一些自定义 javascript 方法让我们假设。

function callMe(){
  //Do some stuff and return.
}

现在我想添加一些功能,我不确定它们是否会被视为回调,但会在某个时候触发 callMe() 正在执行。假设我希望 beforecallMe() 需要在有人调用 callMe() 时立即执行 方法

function beforecallMe(){
// Do something and continue with callMe method

}

同样,我想在 callMe 执行完其部分代码后立即调用一个方法,假设方法 afterCallMe() .

function afterCallMe(){
 //Triggered after callMe has executed
}

那么有什么方法可以在回调或任何其他方式中做到这一点。

另外我想知道它是否可以在特定函数将要执行或已经执行时调用其他自定义函数作为回调,有点触发。

例如:有一个方法sendmail(),有时我想调用它sendReport()startaProgram() doSomething() 等等。有什么办法可以做到这一点吗?

有很多方法可以解决这个问题。

这里有两个。

一个使用函数参数和一个内部有函数的对象,然后使用回调。它们都是有效的,但如果你问我,回调会更简单一些。

//you can pass a parameter and
//use that in a switch statement
//to decide what to do
var funcs = {
    start: function(next) {

        switch (next) {
            case 1:
                this.startProgram();
                break;

            case 2:
                this.sendReport();
                break;

            case 3:
                this.doOtherThing();
                break;

            default:
                console.log('do nada');
                break;
        }
    },

    startProgram: function() {
        console.log("starting a program");
    },

    sendReport: function() {
        console.log("sending report");
    },

    doOtherThing: function() {
        console.log("Doing something else");
    }
};

funcs.start(1)
funcs.start()

//Or you can do it with callbacks
function doSomethingElse(callback) {
    console.log("doing something");
    callback();
}

doSomethingElse(function() {
    console.log("I'm a callback!");
});

你可以这样做

function callMe()
{
    beforeCallMe();
    // CallMe code here
    afterCallMe();
}

beforeCallMe() 将在 callMe() 方法的其余部分之前执行,然后 afterCallMe() 将被执行;

您可以定义函数如下:

function callMe(beforeCall, afterCall){
  if(typeof(beforeCall) === "function") beforeCall();

  // Your call me code goes here...

  if(typeof(afterCall) === "function") afterCall();
}

用法:

callMe(); // No callbacks
callMe(null, afterCall); // Will only call the afterCall
callMe(beforeCall, afterCall); // Will call both the beforeCall and afterCall

function beforeCall() {
  // before call function
}
function afterCall() {
  // after call function
}

或者你可以定义为匿名函数:

callMe(function () {
  // before call function
}, function () {
  // after call function
}); 

有一百种方法可以做到这一点。这是一个函数,它将接受 3 个函数,或一个将函数定义为参数的对象。

<script>
    function write(txt) {
        document.getElementById("test").innerHTML = txt;
    }

    function append(txt) {
        var inner = document.getElementById("test").innerHTML;
        document.getElementById("test").innerHTML = inner + "<br>" + txt;
    }

    function callMe(callFunctionOrObject, callBefore, callAfter) {
        if (!callFunctionOrObject) return;

        if (typeof callFunctionOrObject === "object") {
            if (typeof callFunctionOrObject.callBefore === "function") {
                callFunctionOrObject.callBefore();
            }
            if (typeof callFunctionOrObject.call === "function") {
                callFunctionOrObject.call();
            }
            if (typeof callFunctionOrObject.callAfter === "function") {
                callFunctionOrObject.callAfter();
            }
        }
        else if (typeof callFunctionOrObject === "function") {
            if (typeof callBefore === "function") {
                callBefore();
            }
            callFunctionOrObject();
            if (typeof callAfter === "function") {
                callAfter();
            }
        }
    }

    //EXAMPLE USAGE
    append("First Test");
    callMe({
        "callBefore": function() { append("Before call 1"); },
        "call": function() { append("call 1"); },
        "callAfter": function() { append("After call 1"); }
    });

    append("Second Test");
    callMe(
        function() { append("call 2"); },
        function() { append("Before call 2"); },
        function() { append("After call 2"); }
    );
</script>

<div id="test"></div>

The Fiddle

您可以动态地执行此操作,设置一个之前 and/or 之后的处理程序,以及为每个函数设置上下文参数。

下面的代码有 2 个重要功能 setupFunctionTriggersremoveFunctionTriggers。其余代码和 html 只是为了展示如何使用这些功能。

使用的一些关键技术:

  1. 命名函数可以像变量一样对待。它的"value" can be copied read and assigned to(复制和替换)。
  2. 使用new Function()执行动态代码。
  3. new Function('return '+funcName+';')(); 将 return 命名函数本身。
  4. new Function('func', funcName+'=func;')(wrapperFunc); 将用新函数替换该函数。

function setupFunctionTriggers(funcName, before, after, beforeArgs, afterArgs) {
  var func = new Function('return '+funcName+';')();
  var wrapperFunc = function() {
    if(before instanceof Function)
      before.apply(this, beforeArgs);
    
    var ret = func.apply(this, arguments);

    if(after instanceof Function)
      after.apply(this, afterArgs);

    return ret;
  };

  new Function('func', funcName+'=func;')(wrapperFunc);
  return func;
}

function removeFunctionTriggers(funcName, original) {
  new Function('func', funcName+'=func;')(original);
}



var log = '';

function callMe(val) {
  log += 'Inside callMe(' + val + ')\n';
  return 'Called me!';
}

function before(val) {
  log += 'Before callMe, with val=' + val + '\n';
}

function after() {
  log += 'After callMe\n';
}


log += 'Call normal function\n';
callMe(12);

log += '\nSetup triggers...\n';
var originalCallMe = setupFunctionTriggers('callMe', before , after, ['B4!']);

var ret = callMe(34);
log += 'callMe returned: ' + ret;

log += '\n\nCall original function (triggers still attached)\n';
originalCallMe(56);

log += '\nReverting...\n';
removeFunctionTriggers('callMe', originalCallMe);

callMe(78);

document.getElementById('log').innerHTML = '<pre>'+log+'</pre>';
<span id="log"></span>

我在评论中找到了丹戴维斯在评论中提到的答案。

而 fiddle 同样是

http://jsfiddle.net/3h3f2y93/1/

代码是:

Function.prototype.after=function(fn){
    var f=this;
    return function(){
        return fn.apply(this, arguments), f.apply(this, arguments);
    }
};

Function.prototype.before=function(fn){
    var f=this;
    return function(){
        return f.apply(this, arguments), fn.apply(this, arguments);
    }
};


function say1(){ alert(1); }
function say2(){ alert(2); }
function say3(){ alert(3); }

//say 2 before you say 1 and after you say 3:
 say2.before(say1).after(say3)();