2

我想有一种方法可以为预先存在的功能添加功能,所以我做了这个:

Function.prototype.attachFunction = function(toAttach)
{
    var func = this; //This is the original function, which I want to attack toAttach function to.

    //Can I do this without wrapping it in a self-executing function? What's the difference?
    func = (function()
    {
        return function()
        {
            func();
            toAttach();
        }
    })();

    return func; //Return the newly made function, not really important.    
}

我将它粘贴到 Google Chrome 控制台中,没有错误,但是,它根本没有(或者看起来)改变原始功能。

f = function() {console.log("g");};
f.attachFunction(function(){console.log("New function!");});
f(); //Prints out just "g".
4

6 回答 6

1

attachFunction您在原型上设置的方法Function是一个高阶函数或组合器,它接受一个函数并返回一个新函数。正如预期的那样,它被之后创建的任何函数继承。但是,当它被调用时,它不会f以任何方式改变 的状态,它只是生成一个调用 的新函数f,或者更确切地说是调用函数。

因此,如果您想查看两条console.log消息,您只需调用它返回的函数,如下所示:

f.attachFunction(function(){console.log("hi")})();
或更简单地说:
f.attachFunction(f)();

请注意,虽然函数是对象,但其执行上下文(代码)f并不是f可以直接操作的属性,而是保存在内部属性中。

于 2012-07-14T02:39:29.533 回答
1

执行时attachFunction,它返回一个执行func()和的函数toAttach。但是,如果您将代码更改为以下内容,它将尝试执行这两个函数,而当前旧的 f 仍然在最后被调用。

f = function() {console.log("g");};
f = f.attachFunction(function(){console.log("New function!");});
f(); //Causes an infinite loop since calling func() is the same as calling this()

要合并两个函数,我们需要以相同的方式包装它们,但不是在扩展 Function 时

var func1 = function(){
    console.log('g');
};
var func2 = function(){
    console.log('New function!');
};

func1 = (function(f1,f2){
    return function(){            
        f1();
        f2();
    }
}(func1, func2));

func1(); //Writes out both g and New function!​​​​​​​​​​​​​​​​​​​​

我传入 func1 和 func2 作为参数的原因是为了防止同样的问题进入无限循环。我想在那个时间点保持对这些函数的引用。

辅助函数将如下所示

function combineFunctions(f1, f2){
    return function(){
        f1();
        f2();
    }
}

并且会像这样使用

var f = function() {console.log("g");};
f = combineFunctions(f,function(){console.log("New function!");});
f();
于 2012-07-14T02:42:36.057 回答
0

我刚刚发现了两个问题。

问题1。

f = function() {console.log("g");};
f.attachFunction(function(){console.log("New function!");});
f();

它绝对不起作用,因为attachFunction只是环绕你的原始函数并返回包裹,它不会改变原始函数,这意味着你的f函数仍然f = function() {console.log("g");}

问题 2。

如果您f使用 的结果重新分配,则会发生attachFunctionan 。Maximum call stack size exceeded在 的定义中attachFunction

func = (function()
{
    return function()
    {
        func();
        toAttach();
    }
})();

return func; 

func函数递归地调用自己。

更新

我更喜欢这种方法。

Function.prototype.attachFunction = function(toAttach)
{
    var that = this; 

    func = (function()
    {
        return function()
        {
            that();
            toAttach();
        }
    })();

    return func; //Return the newly made function, not really important.    
}
f = function() {console.log("g");};
f = f.attachFunction(function(){console.log("New function!");});
f();
于 2012-07-14T03:31:41.680 回答
0

Underscore.js 的wrap() 函数应该非常接近你想要的。

于 2012-07-14T01:55:08.853 回答
0

目前,您正在尝试调用一个变量,就好像它是一个函数一样(toAttach是一个变量,并且您在它的另一边打了一些括号)。考虑一下: toAttach可能包含一个函数,但这并不能使它成为一个函数(就像杂货店不是苹果一样)。相反,您需要调用变量中包含的函数。

有几种方法可以做到这一点(尽管这里只有一种或两种适用),但没有一种[正确]方法涉及eval()(生活课程)。

考虑这个线程。将函数名作为字符串传递,然后使用

window[toAttach]();

调用函数。它有点hacky,并且缺乏将函数作为对象传递的技巧,但它确实有效。

或者(完全取决于您的需要)您可以将函数绑定到事件。如果你特别狡猾(为什么不呢?)你可以使用

setTimeout(toAttach, 0);

wheretoAttach是对实际函数的引用(再次)。

最后,也是最好的,我相信,是 Function.call() 方法。使用它,您可以调用填充在变量中的函数,甚至将其传递给this.

toAttach.call([Context]);

函数的上下文在哪里[Context](即在this函数内部时指的是什么,在大多数情况下,可以将其留空以获得所需的范围)。我不能说我已经在您的特定情况下对其进行了测试(这就是为什么我最后将其包括在内),但我相信它应该可以为您提供您正在寻找的结果。

于 2012-07-14T02:01:13.343 回答
0

这是我实现这一目标的尝试,它并不干净,就像它完全在原型中一样,但它可以工作。可能有比我更好的方法。

var bindings={};

function execBindings(func_name) {
    if (bindings[func_name] != undefined) {
        for (var i=0;i<bindings[func_name].length;i++) {
            bindings[func_name][i]();
        }
    }
}

Function.prototype.bind=function(action){
    if (bindings[this.name] == undefined) {
        bindings[this.name]=[];
    }
    bindings[this.name].push(action);
}

然后,使用绑定:

function f() {
    alert("foo");
    execBindings("f");
}

f.bind(function(){
    alert("bar");
});

f.bind(function(){
    alert("test");
});

f();

这导致 3 个警报,按照绑定到函数的顺序。

于 2012-07-14T02:28:38.980 回答