164

我有一个函数,a()我想覆盖它,但还要a()根据上下文按顺序执行原始函数。例如,有时当我生成一个页面时,我会想像这样覆盖:

function a() {
    new_code();
    original_a();
}

有时像这样:

function a() {
    original_a();
    other_new_code();
}

我如何original_a()从覆盖范围内得到它a()?甚至可能吗?

请不要以这种方式提出替代方案,我知道很多。我是专门问这种方式的。

4

12 回答 12

180

你可以这样做:

var a = (function() {
    var original_a = a;

    if (condition) {
        return function() {
            new_code();
            original_a();
        }
    } else {
        return function() {
            original_a();
            other_new_code();
        }
    }
})();

original_a在匿名函数内部声明可以防止它弄乱全局命名空间,但它可以在内部函数中使用。

就像评论中提到的书呆子一样,一定要()在最后加上。您想调用外部函数并将结果(两​​个内部函数之一)存储在 中a,而不是将外部函数本身存储在a.

于 2008-11-17T20:01:58.303 回答
91

代理模式可能会帮助您:

(function() {
    // log all calls to setArray
    var proxied = jQuery.fn.setArray;
    jQuery.fn.setArray = function() {
        console.log( this, arguments );
        return proxied.apply( this, arguments );
    };
})();

上面将其代码包装在一个函数中以隐藏“代理”变量。它将 jQuery 的 setArray 方法保存在一个闭包中并覆盖它。然后代理记录对该方法的所有调用并将调用委托给原始方法。使用 apply(this, arguments) 可以保证调用者不会注意到原始方法和代理方法之间的区别。

于 2008-11-17T20:03:56.193 回答
28

谢谢大家,代理模式真的很有帮助.....实际上我想调用一个全局函数 foo.. 在某些页面中我需要做一些检查。所以我做了以下。

//Saving the original func
var org_foo = window.foo;

//Assigning proxy fucnc
window.foo = function(args){
    //Performing checks
    if(checkCondition(args)){
        //Calling original funcs
        org_foo(args);
    }
};

Thnx 这真的帮助了我

于 2009-11-16T06:56:02.427 回答
11

您可以使用以下构造覆盖函数:

function override(f, g) {
    return function() {
        return g(f);
    };
}

例如:

 a = override(a, function(original_a) {
      if (condition) { new_code(); original_a(); }
      else { original_a(); other_new_code(); }
 });

编辑:修正了一个错字。

于 2010-01-31T05:33:55.617 回答
4

传递任意参数:

a = override(a, function(original_a) {
    if (condition) { new_code(); original_a.apply(this, arguments) ; }
    else { original_a.apply(this, arguments); other_new_code(); }
});
于 2012-01-31T17:24:27.047 回答
3

@Matthew Crumley 提供的答案是利用立即调用的函数表达式,将旧的“a”函数关闭到返回函数的执行上下文中。我认为这是最好的答案,但就个人而言,我更愿意将函数“a”作为参数传递给 IIFE。我觉得比较好理解。

   var a = (function(original_a) {
        if (condition) {
            return function() {
                new_code();
                original_a();
            }
        } else {
            return function() {
                original_a();
                other_new_code();
            }
        }
    })(a);
于 2016-11-17T12:49:40.640 回答
2

上面的示例没有正确应用thisarguments正确传递给函数覆盖。下划线 _.wrap() 包装现有函数,正确应用this和传递arguments。见:http ://underscorejs.org/#wrap

于 2012-09-19T02:00:24.980 回答
0

我有一些由其他人编写的代码,并想在我在代码中找不到的函数中添加一行。因此,作为一种解决方法,我想覆盖它。

不过,没有一个解决方案对我有用。

以下是我的情况:

if (typeof originalFunction === "undefined") {
    originalFunction = targetFunction;
    targetFunction = function(x, y) {
        //Your code
        originalFunction(a, b);
        //Your Code
    };  
}
于 2015-11-22T17:34:17.830 回答
0

我为类似的场景创建了一个小助手,因为我经常需要覆盖多个库中的函数。这个助手接受一个“命名空间”(函数容器)、函数名和覆盖函数。它将用新函数替换引用命名空间中的原始函数。

新函数接受原始函数作为第一个参数,原始函数参数作为其余参数。它将每次都保留上下文。它也支持 void 和 non-void 函数。

function overrideFunction(namespace, baseFuncName, func) {
    var originalFn = namespace[baseFuncName];
    namespace[baseFuncName] = function () {
        return func.apply(this, [originalFn.bind(this)].concat(Array.prototype.slice.call(arguments, 0)));
    };
}

以 Bootstrap 为例:

overrideFunction($.fn.popover.Constructor.prototype, 'leave', function(baseFn, obj) {
    // ... do stuff before base call
    baseFn(obj);
    // ... do stuff after base call
});

我没有创建任何性能测试。它可能会增加一些不必要的开销,这可能是也可能不是大问题,具体取决于场景。

于 2015-11-25T09:19:18.883 回答
0

在我看来,最重要的答案是不可读/不可维护的,其他答案没有正确绑定上下文。这是一个使用 ES6 语法来解决这两个问题的可读解决方案。

const orginial = someObject.foo;
someObject.foo = function() {
  if (condition) orginial.bind(this)(...arguments);
};
于 2016-09-12T01:41:10.377 回答
0

所以我的答案最终成为一个解决方案,允许我使用指向原始对象的 _this 变量。我创建了一个“Square”的新实例,但是我讨厌“Square”生成它的大小的方式。我认为它应该符合我的特定需求。然而,为了做到这一点,我需要广场有一个更新的“GetSize”函数,该函数的内部调用广场中已经存在的其他函数,例如this.height、this.GetVolume()。但为了做到这一点,我需要在没有任何疯狂黑客的情况下做到这一点。所以这是我的解决方案。

其他一些对象初始化器或辅助函数。

this.viewer = new Autodesk.Viewing.Private.GuiViewer3D(
  this.viewerContainer)
var viewer = this.viewer;
viewer.updateToolbarButtons =  this.updateToolbarButtons(viewer);

在另一个对象中起作用。

updateToolbarButtons = function(viewer) {
  var _viewer = viewer;
  return function(width, height){ 
blah blah black sheep I can refer to this.anything();
}
};
于 2018-08-30T06:17:05.617 回答
0

不确定它是否适用于所有情况,但在我们的例子中,我们试图覆盖describeJest 中的函数,以便我们可以解析名称并在describe它满足某些条件时跳过整个块。

这对我们有用:

function describe( name, callback ) {
  if ( name.includes( "skip" ) )
    return this.describe.skip( name, callback );
  else
    return this.describe( name, callback );
}

这里有两件事很关键:

  1. 我们不使用箭头函数() =>

    箭头函数更改对的引用this,我们需要将其作为文件的this.

  2. 使用this.describeandthis.describe.skip而不是describeand describe.skip

同样,不确定它对任何人是否有价值,但我们最初试图摆脱Matthew Crumley 的 出色答案,但需要使我们的方法成为函数并接受参数以便在条件中解析它们。

于 2020-06-05T21:54:23.290 回答