为什么这个扩展不起作用?

时间:2012-07-14 01:07:55

标签: javascript function prototype

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

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".

6 个答案:

答案 0 :(得分:1)

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

所以,如果你想看到两个console.log消息,你只需要调用它返回的函数,如下所示:

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

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

答案 1 :(得分:1)

执行attachFunction时,会返回执行func()toAttach的函数。但是,如果您将代码更改为以下代码,它将尝试执行这两个函数,其中当前仍旧调用旧函数。

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

有几种方法可以做到这一点(尽管这里只有一两个方法适用),[右]方式都不涉及eval()(生活课程)。

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

window[toAttach]();

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

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

setTimeout(toAttach, 0);

其中toAttach是对实际功能的引用(再次)。

最后,我认为最好是Function.call()方法。使用此方法,您可以调用填充在变量中的函数,甚至可以为this传递上下文。

toAttach.call([Context]);

其中[Context]是函数的上下文(即函数内部this引用的内容,在大多数情况下,它可以留空以获得所需的范围)。我不能说我已经在你的某些情况下对它进行了测试(因此我最后将其包括在内),但我相信它应该会给你你正在寻找的结果。

答案 4 :(得分: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个警报,按照顺序绑定到该功能。

答案 5 :(得分:0)

我刚发现有两个问题。

问题1。

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

它肯定不起作用,导致attachFunction只是环绕原始函数并返回包装,它不会改变原始函数,这意味着你的f函数仍然是{{1 }}

问题2。

如果您使用f = function() {console.log("g");}的结果重新分配f,则会出现attachFunction。在Maximum call stack size exceeded

的定义中
attachFunction

func = (function() { return function() { func(); toAttach(); } })(); return func; 函数递归调用自己。

更新

我更喜欢这种方法。

func