在引用原始函数的同时覆盖 JavaScript 函数

发布于 2024-07-08 16:19:45 字数 436 浏览 10 评论 0原文

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

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

有时像这样:

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

How do I get that original_a() from inside the overriding a ()? 有可能吗?

请不要建议以这种方式覆盖的替代方案,我知道很多。 我是专门问这个方法的。

I have a function, a(), that I want to override, but also have the original a() be performed in an order depending on the context. For example, sometimes when I'm generating a page I'll want to override like this:

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

and sometimes like this:

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

How do I get that original_a() from within the over-riding a()? Is it even possible?

Please don't suggest alternatives to over-riding in this way, I know of many. I'm asking about this way specifically.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

笑饮青盏花 2024-07-15 16:19:45

您可以这样做:

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 中>。

You could do something like this:

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

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

Declaring original_a inside an anonymous function keeps it from cluttering the global namespace, but it's available in the inner functions.

Like Nerdmaster mentioned in the comments, be sure to include the () at the end. You want to call the outer function and store the result (one of the two inner functions) in a, not store the outer function itself in a.

我很坚强 2024-07-15 16:19:45

代理模式可能会帮助您:

(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, argument) 可以保证调用者无法注意到原始方法和代理方法之间的差异。

The Proxy pattern might help you:

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

The above wraps its code in a function to hide the "proxied"-variable. It saves jQuery's setArray-method in a closure and overwrites it. The proxy then logs all calls to the method and delegates the call to the original. Using apply(this, arguments) guarantees that the caller won't be able to notice the difference between the original and the proxied method.

东走西顾 2024-07-15 16:19:45

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

谢谢这真的帮助了我

Thanks guys the proxy pattern really helped.....Actually I wanted to call a global function foo..
In certain pages i need do to some checks. So I did the following.

//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 this really helped me out

半﹌身腐败 2024-07-15 16:19:45

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

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

编辑:修复了拼写错误。

You can override a function using a construct like:

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

For example:

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

Edit: Fixed a typo.

分開簡單 2024-07-15 16:19:45

传递任意参数:

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

Passing arbitrary arguments:

a = override(a, function(original_a) {
    if (condition) { new_code(); original_a.apply(this, arguments) ; }
    else { original_a.apply(this, arguments); other_new_code(); }
});
欢烬 2024-07-15 16:19:45

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

The answer that @Matthew Crumley provides is making use of the immediately invoked function expressions, to close the older 'a' function into the execution context of the returned function. I think this was the best answer, but personally, I would prefer passing the function 'a' as an argument to IIFE. I think it is more understandable.

   var a = (function(original_a) {
        if (condition) {
            return function() {
                new_code();
                original_a();
            }
        } else {
            return function() {
                original_a();
                other_new_code();
            }
        }
    })(a);
無心 2024-07-15 16:19:45

上面的示例没有正确应用 this 或将参数正确传递给函数重写。 下划线_.wrap() 包装现有函数,应用this 并正确传递参数。 请参阅:http://underscorejs.org/#wrap

The examples above don't correctly apply this or pass arguments correctly to the function override. Underscore _.wrap() wraps existing functions, applies this and passes arguments correctly. See: http://underscorejs.org/#wrap

画▽骨i 2024-07-15 16:19:45

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

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

In my opinion the top answers are not readable/maintainable, and the other answers do not properly bind context. Here's a readable solution using ES6 syntax to solve both these problems.

const orginial = someObject.foo;
someObject.foo = function() {
  if (condition) orginial.bind(this)(...arguments);
};
星星的轨迹 2024-07-15 16:19:45

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

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

以下是对我的案例有效的方法:

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

I had some code written by someone else and wanted to add a line to a function which i could not find in the code. So as a workaround I wanted to override it.

None of the solutions worked for me though.

Here is what worked in my case:

if (typeof originalFunction === "undefined") {
    originalFunction = targetFunction;
    targetFunction = function(x, y) {
        //Your code
        originalFunction(a, b);
        //Your Code
    };  
}
日记撕了你也走了 2024-07-15 16:19:45

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

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

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

I've created a small helper for a similar scenario because I often needed to override functions from several libraries. This helper accepts a "namespace" (the function container), the function name, and the overriding function. It will replace the original function in the referred namespace with the new one.

The new function accepts the original function as the first argument, and the original functions arguments as the rest. It will preserve the context everytime. It supports void and non-void functions as well.

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

Usage for example with Bootstrap:

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

I didn't create any performance tests though. It can possibly add some unwanted overhead which can or cannot be a big deal, depending on scenarios.

时光与爱终年不遇 2024-07-15 16:19:45

所以我的答案最终是一个允许我使用指向原始对象的 _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();
}
};

So my answer ended up being a solution that allows me to use the _this variable pointing to the original object.
I create a new instance of a "Square" however I hated the way the "Square" generated it's size. I thought it should follow my specific needs. However in order to do so I needed the square to have an updated "GetSize" function with the internals of that function calling other functions already existing in the square such as this.height, this.GetVolume(). But in order to do so I needed to do this without any crazy hacks. So here is my solution.

Some other Object initializer or helper function.

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

Function in the other object.

updateToolbarButtons = function(viewer) {
  var _viewer = viewer;
  return function(width, height){ 
blah blah black sheep I can refer to this.anything();
}
};
橪书 2024-07-15 16:19:45

不确定它是否适用于所有情况,但在我们的例子中,我们尝试重写 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 >.

再次强调,不确定它对任何人都有价值,但我们最初试图摆脱 Matthew Crumley 的 很好的答案,但需要使我们的方法成为一个函数并接受参数以便在条件中解析它们。

Not sure if it'll work in all circumstances, but in our case, we were trying to override the describe function in Jest so that we can parse the name and skip the whole describe block if it met some criteria.

Here's what worked for us:

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

Two things that are critical here:

  1. We don't use an arrow function () =>.

    Arrow functions change the reference to this and we need that to be the file's this.

  2. The use of this.describe and this.describe.skip instead of just describe and describe.skip.

Again, not sure it's of value to anybody but we originally tried to get away with Matthew Crumley's excellent answer but needed to make our method a function and accept params in order to parse them in the conditional.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文