【问题标题】:Why doesn't this extension work?为什么这个扩展不起作用?
【发布时间】:2012-07-13 21:01:15
【问题描述】:

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

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

【问题讨论】:

  • 嗯。你确定this的值吗?
  • 嗯,原型就是这样工作的,对吧?
  • 始终使用console.log(this) 检查。这是个好习惯
  • 会的。几分钟后,我正在修复其他东西,现在......
  • 一个问题是你只是重新分配func,它不会覆盖函数的值。请记住,func 只是一个指向函数的指针;它不是函数本身。

标签: javascript function prototype


【解决方案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();

【讨论】:

  • 是的,这行得通,但我还是不知道为什么我的方法不行。
  • 您设置了var func = this;,但随后立即将func 设置为等于一个新函数。这个新函数调用func()toAttach()。但是您已将 func 重新定义为新函数,而不是调用函数。调用函数永远不会被覆盖,也不能被覆盖。如果您不创建 func 变量,而是直接分配给 this,您将得到“分配中的左侧无效”。
【解决方案2】:

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

所以,如果您想同时查看 console.log 消息,您只需调用它返回的函数,如下所示:

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

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

【讨论】:

  • 但是我直接修改了f function by func = ...`,不是吗?
  • 不,您只是将局部变量 functhis 重新分配给您的新函数。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

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

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

    window[toAttach]();
    

    调用函数。这有点 hacky,并且缺乏将函数作为对象传递的技巧,但它可以工作。

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

    setTimeout(toAttach, 0);
    

    其中toAttach 是对实际函数的引用(再次)。

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

    toAttach.call([Context]);
    

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

    【讨论】:

    • 我不明白你在说什么!函数 对象,我可以传递它们并调用它们就好了。你的方法也不管用。 :(
    【解决方案5】:

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

    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 个警报,按照绑定到函数的顺序。

    【讨论】:

      【解决方案6】:

      我刚刚发现了两个问题。

      问题 1。

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

      这肯定不行,因为attachFunction 只是将你原来的函数包裹起来并返回,它不会改变原来的函数,这意味着你的f 函数仍然是f = function() {console.log("g");}

      问题 2。

      如果您使用attachFunction 的结果重新分配f,则会出现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();
      

      【讨论】:

      • 好的,我知道,但是,有没有办法在不依赖 return 的情况下真正改变原始函数?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-03
      • 2011-07-17
      • 1970-01-01
      • 1970-01-01
      • 2021-09-26
      相关资源
      最近更新 更多