重写 JavaScript 函数,同时引用原始

我有一个函数,a(),我想覆盖,但也有原来的 a()被执行的顺序取决于上下文。例如,有时当我生成一个页面时,我会想要像下面这样覆盖:

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

有时像这样:

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

我如何从重写的 a()中得到那个 original_a()? 这可能吗?

请不要以这种方式提出替代重写的建议,我知道很多这样的建议,我只是特别询问一下这种方式。

209516 次浏览

你可以这样做:

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可以防止它弄乱全局名称空间,但是它可以在内部函数中使用。

就像 Nerdmaster 在评论中提到的那样,一定要在最后加入 ()。您需要调用外部函数并将 结果(两个内部函数之一)存储在 a中,而不是将外部函数本身存储在 a中。

代理模式可能会帮助你:

(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-method 保存在一个闭包中并覆盖它。然后,代理记录对该方法的所有调用,并将调用委托给原始方法。使用 application (this,参数)可以保证调用方不会注意到原始方法和代理方法之间的差异。

谢谢大家,代理模式真的很有帮助... ... 实际上,我想调用一个全局函数 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);
}
};

谢谢,这真的帮了我大忙

可以使用以下构造重写函数:

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

编辑: 修正了一个打字错误。

通过武断的论点:

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

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

我有一些别人写的代码,并希望添加一行到一个函数,我无法在代码中找到。因此,作为一个变通方案,我想覆盖它。

但是没有一个解决方案对我有效。

以下是我的例子:

if (typeof originalFunction === "undefined") {
originalFunction = targetFunction;
targetFunction = function(x, y) {
//Your code
originalFunction(a, b);
//Your Code
};
}

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

新函数接受原始函数作为第一个参数,接受原始函数作为其余的参数。它每次都会保留上下文。它还支持 void 和非 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
});

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

在我看来,前几个答案是不可读/不可维护的,其他的答案不能很好地结合上下文。下面是使用 ES6语法解决这两个问题的可读解决方案。

const orginial = someObject.foo;
someObject.foo = function() {
if (condition) orginial.bind(this)(...arguments);
};

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

因此,我的答案最终是一个允许我使用 _ this 变量指向原始对象的解决方案。 我创建了一个“ Square”的新实例,但是我讨厌“ Square”生成它的大小的方式。我觉得它应该符合我的特殊需求。然而,为了做到这一点,我需要正方形具有一个更新的“ GetSize”函数,该函数的内部调用正方形中已经存在的其他函数,比如 this。().但为了做到这一点,我需要这样做,没有任何疯狂的黑客。所以这是我的解决办法。

其他一些 Object 初始值设定项或助手函数。

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

不确定它是否在所有情况下都能正常工作,但是在我们的例子中,我们试图在 Jest 中覆盖 describe函数,这样我们就可以解析名称,如果满足某些条件,就可以跳过整个 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.describethis.describe.skip而不仅仅使用 describedescribe.skip

同样,不确定它是否对任何人都有价值,但是我们最初尝试使用 马修 · 克拉姆利的 答得好,但是需要使我们的方法成为一个函数并接受 params,以便在条件语句中解析它们。